Reputation: 82136
I am trying to decode a base64 encoded EMF image from an XML document in my application and render it on screen, however, it never seems to appear.
If I copy/paste the data from the XML document into Notepad++ and use the Base64 Decode
option and save the file as a .emf
it opens fine in mspaint. So I think the issue is how I am decoding it.
I have tried the following decode methods described in these articles:
How to encode / decode Base 64 string
http://www.swissdelphicenter.ch/torry/showcode.php?id=1223
I have also tried the TIdDecoderMIME
class to no avail.
Does anyone know the most reliable way of decoding a base64 encoded string from XML?
Example
procedure TXmlSerializer.SaveImageFromString(const AValue: string);
var
StrStream: TStringStream;
Decoder: TIdDecoderMIME;
begin
// AValue is base64 encoded string from XML doc
Decoder := TIdDecoderMIME.Create(nil);
try
StrStream := TStringStream.Create(Decoder.DecodeString(AValue));
try
StrStream.SaveToFile('MyPath\Image.emf');
finally
StrStream.Free;
end;
finally
Decoder.Free;
end;
end;
Why is it the above doesn't work but copying the raw data into Notepad++ and decoding & saving as .emf
works?
Upvotes: 3
Views: 9133
Reputation: 6103
TIdDecoderMIME works just fine. Tried and tested. Just look at the code samples provided by Indy.
Also OmniXML has OmniXMLUtils.pas unit with various utilities functions for XML. Inside you can find standalone Base64 encode/decode function. You can copy paste them or use them as they are.
Otherwise post the code using TIdDecoderMIME. It must be an error in you code.
EDIT:
You must watch out that you write the string to stream as single byte order. Base64 works on bytes (ASCII chars) and will not work correctly if you supply it with the 2 byte unicode string. If you take an Base64 encoded sequence as string and write it to stream as it is you will have an error, because the lenghth of such stream will be twice as long as the original was.
You can take TStringStream or use AnsiStrings for the task. As long as you stick to that the encode / decode will work correctly.
You can also use my SimpleStorage which does all the work for you. Reading an image from XML comes to such simple task as:
Jpeg := TJPEGImage.Create;
try
Jpeg.LoadFromStream(SrcStorage.Get('Image').Filter('gzip').AsBinary.Stream);
finally
Jpeg.Free;
end;
Easy isn't it (and it is also decompressed in the process). :)
Upvotes: 2
Reputation: 53880
Ensure that you're decoding just the attribute value and not the entire XML.
In your code, be sure to set the position of the stream to 0 before read from it.
StrStream.Seek(0, soFromBeginning);
I'm not familiar with the SaveToFile() method of TStringStream. Are you sure about that?
Also, since Delphi 2010 supports unicode strings, you might want to use AnsiStrings when handling binary data. Be careful when mixing multi-byte character types with single byte data.
Upvotes: 0
Reputation: 2960
You're using a string to store binary data; Delphi 2010's unicode-ness could be to "blame" here.
Try using a base64 decoder which supports decoding to a stream, and decode directly to a TFileStream
; I use JclMime
(part of Jedi's JCL), but I'd be surprised if there wasn't an Indy MIME method which works on streams instead of strings.
As JclMime
only supports stream-to-stream decoding, I use the following wrapper when decoding base64 data from XML payloads:
procedure MimeDecode(const inputString: string; const outputStream: Tstream);
var
ss: TStringStream;
begin
ss := TStringStream.Create(inputString);
try
JclMime.MimeDecodeStream(ss, outputStream);
finally
ss.free;
end;
end;
Upvotes: 7