0

I have an application written in Delphi 10.1 using REST Datasnap.

This application includes a Client and Server.

The Client is a mobile application (Android) and the Server is a Windows Service that's is connected to a firebird database.

I have an Object:-

TJob = class(TObject)
  private
    FID: Integer;
    FThe_Name: String;
    FImage: TMemoryStream;
  public
    constructor Create;
    destructor Destroy;
  end;

constructor TJob.Create;
begin
  inherited;
  FImage := TMemoryStream.Create;
end;

destructor TJob.Destroy;
begin
  FreeAndNil(FImage);
  inherited;
end;

I get an access violation when I try to save the image on the server to the DB and when I try and open and display the image on the client.

I have a standalone multidevice application that use the same functionality(Getting, Saving and displaying of an Image) as the Client/Server and works.

Client displaying the image on the form:-

if (Job.Image.Size > 0) then
  begin
    rectangle.Fill.Kind := TBrushKind.Bitmap;
    rectangle.Fill.Bitmap.Bitmap.LoadFromStream(Job.Image);
    rectangle.Repaint;
    Layout.Repaint;
  end;

Client getting the Image from the form:-

if not(rectangle.Fill.Bitmap.Bitmap.IsEmpty) then
  begin
    Job.Image.Seek(0, soFromBeginning);
    rectangle.Fill.Bitmap.Bitmap.SaveToStream(Job.Image);
    Job.Image.Position := 0;
  end;

Server Saving the Image to DB:-

  Job.Image.Position := 0;
  (TBlobField(FieldByName('MyImage'))).SaveToStream(Job.Image);

Server getting the Image from DB:-

(TBlobField(FieldByName('MyImage'))).SaveToStream(Job.Image);

The Standalone application works using the same however I get errors when trying to either save or display an image.

I have populated the DB with various formats of images, which I can view in the DB, but not from the Client(AV).

Any ideas on what I've done wrong and examples on how to solve fix?

Thanks

Yuppski
  • 137
  • 2
  • 10
  • There isn't enough code here. We will need to see the complete client code that calls the server method, and the server method code. – Freddie Bell Jun 15 '20 at 13:59
  • This may or may not be a red herring but as I'm passing a TMemorystream does it need to involve Marshalling? I have no idea how that works so examples would be grateful. – Yuppski Jun 15 '20 at 17:51
  • Is the image you are using bigger than 256kb ?, because I had problems passing streams bigger than that, they get truncated, so I had to pass them split in chunks. https://stackoverflow.com/questions/41854631/cant-retrieve-tstreams-bigger-than-around-260-000-bytes-from-a-datasnap-server – Marc Guillot Jun 16 '20 at 06:08
  • Thanks for the pointers Marc. I found and used Base64FromBitmap & BitmapFromBase64. I've updated the main post with my latest source. 1. My client will only handle BMP files (Just to add a standlone app works fine with most types). 2. My Server has an AV when trying to save, calling the BitmapFromBase64(This does not occur on my standlone) – Yuppski Jun 16 '20 at 14:16

1 Answers1

0

Server getting the Image from DB:-

  PngImage := TPngImage.Create;
  MemoryStream := TMemoryStream.Create;
  try
    (TBlobField(FieldByName('Image'))).SaveToStream(MemoryStream);
    MemoryStream.Position := 0;
    PngImage.LoadFromStream(MemoryStream);
    Job.Image_AsStr := Base64FromPngImage(PngImage);
  finally
    MemoryStream.Free;
  end;

Client displaying the image on the form:-

  if (Job.Image_AsStr <> '') then
  begin
    rImage.Fill.Kind := TBrushKind.Bitmap;  
    rImage.Fill.Bitmap.Bitmap := BitmapFromBase64(Job.Image_AsStr);
    rCustomer_Signature.Repaint;
    lCustomer_Signature.Repaint;
  end;

Client getting the Image from the form:-

  if not(rImage.Fill.Bitmap.Bitmap.IsEmpty) then
  begin
    rImage.Fill.Kind := TBrushKind.Bitmap;
    Job.Image_AsStr := Base64FromBitmap(rImage.Fill.Bitmap.Bitmap);
  end
  else
    Job.Image_AsStr := '';

Server Saving the Image to DB:-

if Job.Image_AsStr <> '' then
begin
  MemoryStream := TMemoryStream.Create;
  try
    PngImage := PngImageFromBase64(Job.Image_AsStr);
    PngImage.SaveToStream(MemoryStream);
    MemoryStream.Position := 0;
    Params[1].LoadFromStream(MemoryStream, ftBlob);
  finally
    MemoryStream.Free;
  end;
end
else
  Params[1].Clear;

On my experience the image arrives back at the Server as a PngImage even though its been packaged as a BMP.

I can now confirm that I've installed and tested on a Android phone. *Note. The original question posted was about using a TMemoryStream, these examples uses a String.

Yuppski
  • 137
  • 2
  • 10