Load Image from a Blob DataField (Base64)

Hello,
I store an image in a blob-field by:
'var Img_Base64: string;
begin
Try
Img_Base64:=Img_Logo2.Base64Image;

     DataModule_Client.DataSet_NewLogo.Insert;
     DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString:=Img_Base64;

     DataModule_Client.DataSet_NewLogo.Post;
     DataModule_Client.DataSet_NewLogo.ApplyUpdates;
  Except
     ShowMessage('Error');
  End;

end;'

That works well. Now I am failing to load the image from the blob-field.

I tried to load the blob-content in a TMemoryStream by
MStream:=DataModule_Client.DataSet_NewLogo.CreateBlobStream( (DataModule_Client.DataSet_NewLogo.FieldByName('logo') as TBlobField), bmRead)

But this methode is not available for the TWebDataSet

I tried to store the image as string (Base64Image) and tried on that ways:
Img_Logo1.URL:= 'data:image/png;base64,'+Img_Base64; (Img_Base64 includes the Base64Imgae-String)

or with an TFNCImage
FImg1.Bitmap.LoadFromURL(Img_Base64);

I ask you for support.

Many thanks
Patrick

To save:
DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString:=WebImageControl.DataURL;

To load
WebImageControl.URL := DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString;

Hi Bruno,

thanks for answering. I am sorry, but I am not able to fix it. I tried it on that way, also.

There is a Record in the DataSet, but I cann not handle it.
'procedure TForm_TVclient_Main.WebButton8Click(Sender: TObject);
begin
Img_Logo2.URL:=DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString;
WebMemo2.Lines.Add(IntToStr(DataModule_Client.DataSet_NewLogo.FieldByName('logo_id').AsInteger)); //Check if data in DataSet yes
WebMemo2.Lines.Add(Img_Logo2.URL); //Check if data in DataSet no
WebMemo2.Lines.Add(IntToStr(DataModule_Client.DataSet_NewLogo.FieldByName('logo_id').AsInteger)); //Check if data in DataSet yes
end;'

It looks like that the blob-field is empty. but on the db I can see a value of 1.696 byte.

Can you please support me, I tried to fix that the last days?
Many thanks Patrick

I cannot see an issue here.
Is the active record the correct record you look for when you access it as
DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString;
?

I have a partial success: It works with a string-field, but not with a blob-field.

I save the same value in a string-field and in a blob-flield:
'function TDataModule_Client.Save_NewLogo(Logo_string: string): boolean;
begin
Try
if DataSet_NewLogo.State=dsBrowse then
DataModule_Client.DataSet_NewLogo.Insert;
DataSet_NewLogo.FieldByName('company_id').AsInteger:=DataSet_NewCompany.FieldByName('company_id').AsInteger;
//DataSet_NewLogo.FieldByName('logo_id').AsInteger:=8;
if Logo_string<>'' then begin
DataSet_NewLogo.FieldByName('logo').AsString:=Logo_string;
DataSet_NewLogo.FieldByName('logo_string').AsString:=Logo_string;
end;
DataSet_NewLogo.Post;
DataSet_NewLogo.ApplyUpdates;
Result:= true;
Except
Result:= false;
End;
end;

If I load the image with the sting-field, it works:
procedure TForm_TVclient_Main.Btn_LogoLoadClick(Sender: TObject);
var Img_Base64: string;
begin
DataModule_Client.DataSet_NewLogo.Cancel;
DataModule_Client.DataSet_NewLogo.Open;
Img_Base64:='data:image/png;base64,'+DataModule_Client.DataSet_NewLogo.FieldByName('logo_string').AsString;
Img_Logo2.URL:=Img_Base64;
WebMemo1.Lines.Text:=Img_Base64;
end;

If I do exactly the same with the blob-field I get now record content:
procedure TForm_TVclient_Main.Btn_LogoLoadBlobClick(Sender: TObject);
var Img_Base64: string;
begin
DataModule_Client.DataSet_NewLogo.Cancel;
DataModule_Client.DataSet_NewLogo.Open;
Img_Base64:='data:image/png;base64,'+DataModule_Client.DataSet_NewLogo.FieldByName('logo').AsString;
Img_Logo2.URL:=Img_Base64;
WebMemo2.Lines.Text:=Img_Base64;
end;

Do you have an idea. I would like to realize it with a blob...

Many thanks
Patrick

What exact dataset is this?
Is this a text blob?

I use a MariaDB 10.3.21 and I defined the field as blob.

It looks like that the string in the blob-field (i changed it to LongText) is different to the VARChar field. The size is different (LongText=27.688 byte and VARCHAR=18.458 byte) and the signs are also different.

I connect the app via xdata server to the database. I have a unit with all database fields for the xdata app created by the TMS Data Moduler. Maybe it is coursed there...

[Entity]
[Table('company_logo')]
[Id('Flogo_id', TIdGenerator.IdentityOrSequence)]
Tcompany_logo = class
private
[Column('logo_id', [TColumnProp.Required, TColumnProp.NoInsert, TColumnProp.NoUpdate])]
Flogo_id: Integer;

[Column('company_id', [])]
Fcompany_id: Nullable<Integer>;

[Column('logo', [TColumnProp.Lazy])]
Flogo: TBlob;

[Column('logo_string', [], 21800)]
Flogo_string: Nullable<string>;

public
property logo_id: Integer read Flogo_id write Flogo_id;
property company_id: Nullable read Fcompany_id write Fcompany_id;
property logo: TBlob read Flogo write Flogo;
property logo_string: Nullable read Flogo_string write Flogo_string;
end;

Is that helpful?

I am nearly sure that my issue is not coursed in the DB_Unit which is created by the TMS Data Moduler. It seems that it is coursed in the field-definition of the TWebDataSet.

Ichanged the field-type of logo_sting to LongText, also. But I did not changed the data-field-definition. Then it worked. I tried to change the definition of the field logo also, but it didn't work.

Then I was so brilliant and changed the name of the field logo in the database, created a new DB_Unit, deleted the field logo from the TWebDataSet and definied a new field as string.

After that, both fields can not store the value of the image_string. I do not know, what I can do know... I can not reproduce it...

If you could send a project that reproduces the issue, that would be helpful.
In any case, if you are always going to save text content in the blob field, add the attribute DBTypeMemo (or DBTypeWideMemo) to your mapping so Aurelius knows it's a memo field:

[DBTypeMemo]
[Column('logo', [TColumnProp.Lazy])]
Flogo: TBlob;

In the dataset, also try to treat it as a memo (or widememo) field.

i have same problem :

Bitmap.URL := 'data:image/jpeg;base64,'+XDataWebDataset.FieldByName('Immagine').AsString;

where Immagine is a blobfield declared in entity source as :

[Column('IMMAGINE', [TColumnProp.Lazy], 80, 0)]
FIMMAGINE: TBlob;

i receive a error :

Failed to execute 'drawImage' on 'CanvasRenderingContext2D': The HTMLImageElement provided is in the 'broken' state.

how solve ?

This works for me but my image is already base64_encode'd.

XDataWebDataset.FieldByName('Immagine').AsString is a TBlob binary field .... how to convert it in base64_encode ?

I believe that Firebird 4 has functions BASE64_ENCODE and BASE64_DECODE.

You can't just get binary data as string.
You need to get it as binary data and encode it as base64 string.
The unit WEBLib.Utils has methods for converting binary arrays to base64 string
Or, more convenient is to store the value already server side as base64 in the DB and then you can directly use it client side.

then you say is more efficient to read image directly from DB in Base64 format ? ok i can store the image in base64 format in a Blob text field ? this procedure go fine to do this ?

Procedure SaveJpegToBlobField(SourceJpgFile:String; pBlobField:TBlobField);
Var JpgImg:TJPEGImage;
  ImgStrm1,ImgStrm2:TMemoryStream;
begin
  Try
    JpgImg:=TJPEGImage.Create();
    ImgStrm1:=TMemoryStream.Create();
    ImgStrm2:=TMemoryStream.Create();

    JpgImg.LoadFromFile(SourceJpgFile);
    JpgImg.SaveToStream(ImgStrm1);
    ImgStrm1.Position:=0;

    TNetEncoding.Base64.Encode(ImgStrm1,ImgStrm2 );
    ImgStrm2.Position:=0;

    pBlobField.LoadFromStream(ImgStrm2);
  Finally
    JpgImg.Free();
    ImgStrm1.Free();
    ImgStrm2.Free();
  End;
end;

in the photo you see imge base64 is correct BUT when do

imgMain.URL:='data:image/jpeg;base64,'+DM0.wdSett.FieldByName('Immagine').AsString;

i have error

  1. message: "Error loading image data:image/jpeg;base64,LwA5AG
  2. stack: "Error: Error loading image data:image/jpeg;base64

On web app i used IMMAGINE as TBlobField an TMemoField with entity

[DBTypeMemo]
[Column('IMMAGINE', [TColumnProp.Lazy])]
FIMMAGINE: TBlob;

WHY ???

Help me please !!!!!!!!!!

as said Karlheinz with this

[Column('logo_string', [], 21800)]
Flogo_string: Nullable;

GO .... BUT ITS NORMAL ? what is the maximum length of string ?
if i have large image like 2000 x 2000 go fine ? the performance is same ??

correct thi bug please my brain fire !!!

Did you do the effort to take the string returned from your dataset field and verify with a tool like: Base64 to Image | Base64 Decode | Base64 Converter | Base64
that the data URL you assign to the image is a valid image data URL?
If it isn't, well, then there is something wrong with the data in the DB field and you should check that.

Bruno i said all go fine only if in my entity i use String type NOT blob ok ? and it is your bug i think or my mistake ...
Then how is the maximum size of a string ? i used to test 21800 but its enougth ? if i have large images big images what size i can use ?