Search code examples
xmldelphidelphi-10.2-tokyo

TPicture from MyBase Xml file


Using Delphi 10.2 I right-click on a TClientDataSet and choose 'Save to MyBase Xml UTF-8 table.' I now have an XML file with this format:

<ROW NAME="Angel Fish" SIZE="2" WEIGHT="2" AREA="Computer Aquariums" BMP="AQAAAfY+AABCTfY+AAAAAAAAdgAAACgAAADIAAAAoAAAAAEA ...

The BMP field is defined as:

<FIELD attrname="BMP" fieldtype="bin.hex" SUBTYPE="TypedBinary" WIDTH="1"/>

I'm trying to convert what I believe to be a Base64 string representation of a binary bitmap file into a picture. So far I've got this:

uses 
  XMLDoc, Vcl.ComCtrls, XMLIntf, IdCoder, IdCoderMIME, IdGlobal,
  Vcl.ExtCtrls;

procedure TForm2.Button1Click(Sender: TObject);
var Doc:TXMLDocument;
First:IXMLNode;
Str:String;
Bytes: TIdBytes;
Pic:TPicture;
Stream:TMemoryStream;
Writer: TBinaryWriter;

begin
Doc:=TXMLDocument.Create(Self);
Doc.FileName:='D:\temp\ClientDataSet2.xml';
Doc.Active:=true;

First:=Doc.DocumentElement.ChildNodes['ROWDATA'].ChildNodes.First;
Str:=First.Attributes['BMP'];

Bytes:=TIdDecoderMIME.DecodeBytes(Str);
Stream:=TMemoryStream.Create;
Writer:=TBinaryWriter.Create(Stream);

Writer.Write(TBytes(Bytes));
Stream.Position:=0;

Pic:=TPicture.Create;
Pic.LoadFromStream(Stream);

Image1.Picture:=Pic;

RichEdit1.Text:=Str;
end;

However, TPicture.LoadFromStream throws this exception:

First chance exception at $74DCCBB2. Exception class EInvalidGraphic with message 'Unsupported stream format'.

Could anybody please tell me what I'm doing wrong? Many thanks.


Solution

  • The base64 string you showed decodes to binary data that begins with 8 bytes (0x01 0x00 0x00 0x01 0xF6 0x3E 0x00 0x00) before the actual BMP data (0x42 0x4D ...) . The subtype of the BMP attribute is TypedBinary, so this is likely some kind of metadata header to indicate the data is a BMP image. You need to omit those beginning bytes before loading the stream data into TPicture.

    BTW, TPicture.LoadFromStream() just calls TPicture.Bitmap.LoadFromStream(), so you should replace TPicture with TBitmap instead:

    Bmp := TBitmap.Create;
    try
      Bmp.LoadFromStream(Stream); 
      Image1.Picture.Assign(Bmp);
    finally
      Bmp.Free;
    end;