Bonjour,
Je dois encoder une image en Base 64 pour effectuer un transfert vers un webservice en XML.
Comment faire ??
Merci
Bonjour,
Je dois encoder une image en Base 64 pour effectuer un transfert vers un webservice en XML.
Comment faire ??
Merci
En utilisant une fonction encode64 qui doit être disponible avec les composants XML ou ça (en le modifiant pour utiliser un stream): http://www.swissdelphicenter.ch/torry/showcode.php?id=1524
En gros, tu enregistres ton image dans un TMemoryStream.
Ensuite, tu récupère le contenu de celui par 3 octets, que tu stocke chaque fois dans un LongWord (4ème octet à 0 bien entendu).
Après, tu fais qutre and binaires pour récupérer les 24 bits par 6 (6 bits = base 64).
Tu n'as plus qu'à stocker ces 6 bits dans un Byte (deux derniers bits à 0) et finalement récupérer le Xème caractère d'une chaîne de 64 caractère contenant les caractères de ta base.
Attention : après avoir récupéré les 3 octets, tu dois les inverser pour obtenir le format Big Endian.
Au niveau du code, ça devrait donner quelque chose comme ça :
Tu noteras qu'avant l'appel à cette fonction, tu dois vérifier que ton stream possède bien un multiple de 3 octets. Si ce n'est pas le cas, tu dois ajouter les 0 manquant au début.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 function StreamToBase64(Stream : TStream) : string; type TTroisOctets = record // A cause du format Big Endian case integer of 0 : (Int : LongWord); 1 : (Bytes : array[0..3] of Byte); end; const Base64 : string = '01234567789ABCDEFGH...'; // tu dois avoir 64 caractères var TroisOctets : record; SixBits : Byte; begin Stream.Seek(0, soFromBeginning); Result := ''; while Stream.Position < Stream.Size do begin Stream.ReadBuffer(TroisOctets, 3); // Ici on va renverser les quatre octets de TroisOctets TroisOctets.Bytes[3] := TroisOctets.Bytes[0]; TroisOctets.Bytes[0] := TroisOctets.Bytes[1]; TroisOctets.Bytes[1] := TroisOctets.Bytes[2]; TroisOctets.Bytes[2] := TroisOctets.Bytes[0]; TroisOctets.Bytes[0] := 0; // Fin du renversement SixBits := Byte(TroisOctets.Int and 63); // bits 0-5 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 4032) shr 6); // bits 6-11 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 258048) shr 12); // bits 12-17 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 16515072) shr 16); // bits 18-23 Result := Result+Base64[SixBits]; end; end;
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Merci à vous deux, je pense que la méthode de sjrd me semble la plus aproprié, je vais donc tester cette méthode la (t'inquietes pas cpdump, j'avais commencé à transformer la fonction de Torry, mais c'était pas gagné).
juste quelques questions ca :je comprend pas comment ca marche, en plus on peu pas declarer des array dans un record
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5 TTroisOctets = record // A cause du format Big Endian case integer of 0 : (Int : LongWord); 1 : (Bytes : array[0..3] of Byte); end;[EDIT] ahh, ben non ca passe si il y a pas de case, GG le compilo pr le message
[/EDIT]
Bon, ca mis a part, ce que je pige pas c'est comment il trouve la valeur de 'integer' (case integer of...).
Si tu peux m'éclairer, merci.
Voila, je me suis permis d'interpréter ton code comme suit :
Comme ca ca compile mais je ne sais pas si je fais une bétise en virant le case.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36 function TMenuPrincipal.StreamToBase64(Stream : TStream) : string; type TTroisOctets = record // A cause du format Big Endian Int : LongWord; Bytes : array[0..3] of Byte; end; var TroisOctets : TTroisOctets; SixBits : Byte; Bytez : array[0..3] of Byte; const Base64 : string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/'; begin Stream.Seek(0, soFromBeginning); Result := ''; while Stream.Position < Stream.Size do begin Stream.ReadBuffer(TroisOctets.Bytes, 3); // Ici on va renverser les quatre octets de TroisOctets TroisOctets.Bytes[3] := TroisOctets.Bytes[0]; TroisOctets.Bytes[0] := TroisOctets.Bytes[1]; TroisOctets.Bytes[1] := TroisOctets.Bytes[2]; TroisOctets.Bytes[2] := TroisOctets.Bytes[0]; TroisOctets.Bytes[0] := 0; // Fin du renversement SixBits := Byte(TroisOctets.Int and 63); // bits 0-5 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 4032) shr 6); // bits 6-11 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 258048) shr 12); // bits 12-17 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 16515072) shr 16); // bits 18-23 Result := Result+Base64[SixBits]; end; end;
Merci, si ca marche je mettrai en résolu, en att je teste.
A dans quelques minutes![]()
Erg, ca bloque sur la ligne
La première.
Code : Sélectionner tout - Visualiser dans une fenêtre à part Result := Result+Base64[SixBits];
le message c'est :
SixBits vaut 0 à ce moment laIndex was outside the bounds of the array![]()
Merci,
C'est une construction qui permet d'avoir deux suites de champs qui sont enregistrés au même endroit. Donc si tu modifies Int, les Bytes seront modifiés aussi et vice versa. En fait Bytes[0] à la même adresse que IntEnvoyé par Harry
Tu dis qu'on ne peut pas mettre de tableau dans un record, c'est faux ; j'en suis absolument certain.
Par contre il ne faut surtout pas supprimer le case integer of, car dans mon code je me base justement sur let fait que Int et Bytes ont même adresse.
Es-tu certain que le compilo n'accepte pas le code tel que je l'ai écrit ? Si c'est bien le cas peux-tu me dire quel est le message exact du compilo et à quel endroit ?
Pour ce qui est de la valeur de integer, il s'en fout. C'est la construction qui impose ce truc. En fait tu pourrais aussi bien mettre n'importe quel type ordinal (donc pas de chaîne), en adaptant les valeurs possibles. Tu peux même mettre boolean avec True et False !
Voilà j'espère que j'ai été clairsinon n'hésite pas à poser d'autres questions
.
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
J'ai repris ton code d'origine et j'ai juste complété la chaine de 64 caractères et le compilateur s'arrete sur :
Avec le message
Code : Sélectionner tout - Visualiser dans une fenêtre à part 1 : (Bytes : array[0..3] of Byte);
Voila, j'espere que tu pourras m'aider.[Erreur] Menu.pas(1040): E2418 Le type 'Array' nécessite une initialisation - interdite dans un enregistrement variant
Merci,
A ++
[Edit] Remarque : je travaille sous Delphi 2005 en VCL, j'ai essaye ton code sous Delphi 4 et il compile après avoir modifié la declaration de variables comme suit :[/Edit]
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2 var TroisOctets : TTroisOctets; SixBits : Byte;
Envoyé par Harry
erreur d'inattention
En effet c'est TTroisOctets le type.
Apparemment c'est une évolution du langage sour D2005. C'est vrai que j'ai pas encore utilisé cette syntaxe sour D2005.
Je te propose ceci alors :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34 function StreamToBase64(Stream : TStream) : string; type TTroisOctets = record // A cause du format Big Endian case integer of 0 : (Int : LongWord); 1 : (Byte0, Byte1, Byte2, Byte3 : Byte); end; const Base64 : string = '01234567789ABCDEFGH...'; // tu dois avoir 64 caractères var TroisOctets : TTroisOctets; SixBits : Byte; begin Stream.Seek(0, soFromBeginning); Result := ''; while Stream.Position < Stream.Size do begin Stream.ReadBuffer(TroisOctets, 3); // Ici on va renverser les quatre octets de TroisOctets TroisOctets.Byte3 := TroisOctets.Byte0; TroisOctets.Byte0 := TroisOctets.Byte1; TroisOctets.Byte1 := TroisOctets.Byte2; TroisOctets.Byte2 := TroisOctets.Byte0; TroisOctets.Byte0 := 0; // Fin du renversement SixBits := Byte(TroisOctets.Int and 63); // bits 0-5 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 4032) shr 6); // bits 6-11 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 258048) shr 12); // bits 12-17 Result := Result+Base64[SixBits]; SixBits := Byte((TroisOctets.Int and 16515072) shr 16); // bits 18-23 Result := Result+Base64[SixBits]; end; end;
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Merci, ca accepte la déclaration de variables come ca![]()
Par contre je suis coincé sur :
Le message rendu par le compilateur est :
Code : Sélectionner tout - Visualiser dans une fenêtre à part Stream.ReadBuffer(TroisOctets, 3);
Merci,[Erreur] Menu.pas(1051): E2250 Aucune version surchargée de 'ReadBuffer' ne peut être appelée avec ces arguments
Et désolé de te faire debugger comme ca, mais l'aide de delphi 2005 est un peu embrouillé du fait du mélange de languages et en plus orienté fortement vers le C#.
Aïe. Ca c'est vraiment bizarre
Essaye ceci :
Et si pas ceci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part Stream.ReadBuffer(@TroisOctets, 3);
Mais j'ai aucune garantie
Code : Sélectionner tout - Visualiser dans une fenêtre à part Stream.ReadBuffer(TroisOctets^, 3);
Au pire, ajoute une variable de type LongWord comme ceci :
end;
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14 function StreamToBase64(Stream : TStream) : string; ... var LgWord : LongWord; TroisOctets : TTroisOctets; SixBits : Byte; begin ... while Stream.Position < Stream.Size do begin Stream.ReadBuffer(LgWord, 3); TroisOctets.Int := LgWord; ... end; end;
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Yess, on y est presque, tes 2 premiers idées ne passent pas, par contre le 'Au pire' lui, ca marche niquel (mais pourquoi j'y ai pas pensé), enfin ca compile niquel.
Lors de l'execution le code s'arrete sur
(le premier)
Code : Sélectionner tout - Visualiser dans une fenêtre à part Result := Result+Base64[SixBits];
avec comme message d'erreur :
Merci,Index was outside bounds of the array
A++
Arf ! Idiot que je suis !
Il faut mettre Base64[SixBits+1]
On va y arriver![]()
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Merci![]()
Ca marche presque, juste ca bloque au dernier
Avec le meme message.
Code : Sélectionner tout - Visualiser dans une fenêtre à part Result := Result+Base64[SixBits +1];
Mais c'est peut etre de ma faute! voici le code que j'ai fait pour ajouter le 0 devant pour que le stream soit un multiple de 3 en longeur.
decal est un byte avec 0 dedans.
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7 decal := 0; streambis := TMemoryStream.Create; if (i mod 3) > 0 then begin streambis.Write(decal,sizeof(decal)); streambis.CopyFrom(Stream, 0); stream := streambis; end;
je sais pas pourquoi mais j'ai l'impression de chercher midi a 14h![]()
Merci
Avec le décalage de streams, il fautEnvoyé par Harry
Mais je te conseille plutôt ce code-ci :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16 var Zero : integer; StreamBis : TStream; ... Zero := 0; if Stream.Size mod 3 > 0 then begin StreamBis := TMemoryStream.Create; try StreamBis.Write(Zero, 3 - Stream.Size mod 3); StreamBis.CopyFrom(Stream, 0); Stream.Seek(0, soFromBeginning); Stream.CopyFrom(StreamBis, 0); finally StreamBis.Free; end; end;
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Ok, en fait le problème persiste, voici le code dans son état actuel :
Code : Sélectionner tout - Visualiser dans une fenêtre à part
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56 function TMenuPrincipal.StreamToBase64(Stream : TStream) : string; type TTroisOctets = record // A cause du format Big Endian case integer of 0 : (Int : LongWord); 1 : (Byte0, Byte1, Byte2, Byte3 : Byte); end; const Base64 : string = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz+/'; //64 caractères var TroisOctets : TTroisOctets; SixBits : Byte; LgWord : LongWord; i, Zero : integer; Streambis : TStream; begin Zero := 0; if Stream.Size mod 3 > 0 then begin StreamBis := TMemoryStream.Create; try i := (3 - (Stream.Size mod 3)); StreamBis.Write(Zero, i); StreamBis.CopyFrom(Stream, 0); Stream.Seek(0, soFromBeginning); Stream.CopyFrom(StreamBis, 0); finally StreamBis.Free; end; end; i := stream.Size; Showmessage(IntToStr(i)); Stream.Seek(0, soFromBeginning); Result := ''; while Stream.Position < Stream.Size do begin Stream.ReadBuffer(LgWord, 3); TroisOctets.Int := LgWord; // Ici on va renverser les quatre octets de TroisOctets TroisOctets.Byte3 := TroisOctets.Byte0; TroisOctets.Byte0 := TroisOctets.Byte1; TroisOctets.Byte1 := TroisOctets.Byte2; TroisOctets.Byte2 := TroisOctets.Byte0; TroisOctets.Byte0 := 0; // Fin du renversement SixBits := Byte(TroisOctets.Int and 63); // bits 0-5 Result := Result+Base64[SixBits +1]; SixBits := Byte((TroisOctets.Int and 4032) shr 6); // bits 6-11 Result := Result+Base64[SixBits +1]; SixBits := Byte((TroisOctets.Int and 258048) shr 12); // bits 12-17 Result := Result+Base64[SixBits +1]; SixBits := Byte((TroisOctets.Int and 16515072) shr 16); // bits 18-23 Result := Result+Base64[SixBits +1]; end; end;
A l'execution ca plante sur la dernière ligne :
avec comme message :
Code : Sélectionner tout - Visualiser dans une fenêtre à part Result := Result+Base64[SixBits +1];
Merci pour toutIndex was outside bounds of the array![]()
Est ce que tu utilises un composant xml pour gérer tes fichiers xml ? parce les fonctions encode64 sont intégrés dans les compostants xml. Ca serais plus rapide que de perder son temps à chercher un bug dans le code ta fonction.
J'utilise le composant TXMLDocument, mais c'est une photo que je veux encoder en base 64.
Et je n'ai pas trouvé la moindre méthode pour encoder en Base 64 avec ce composant![]()
Si il y en a un bien caché je suis toute ouie![]()
Généralement les composants xml ont des fonction encode/decode64 puisque c'est le moyen de stocker les infos binaires. C'est disponible aussi avec les composants Internet type Indy ou ICS.
Sinon regarde ici: http://www.szutils.net/Delphi/Delphi.php
Évalue un peu la valeur de SixBits juste avant d'exécuter cette instruction.Envoyé par Harry
sjrd, ancien rédacteur/modérateur Delphi.
Auteur de Scala.js, le compilateur de Scala vers JavaScript, et directeur technique du Scala Center à l'EPFL.
Découvrez Mes tutoriels.
Partager