Search code examples
arraysdelphiblobmemorystreamdelphi-xe3

How to save multiple images from database to TMemoryStream at runtime and extract them later on


I am creating a project at delphi(RAD Studio). There are images stored at database table at some rows. I want to extract images at runtime (for which I am using Array of TMemoryStream) and show them at frxReport.

My code snippet as follows

Public variable TStream is declared as

Stream2 : Array of TStream; i,k: integer

Code segment for view button click event, which is placed on MainForm and expected to show frxReport.

`

procedure TFrmMain.btnViewClick(Sender: TObject);
begin
    i := 0;
    k := 0;
    UniTable1.SQL.Text := 'Select * from userplays order by id';
    UniTable1.Execute;

    rowcount := UniTable1.RecordCount;

    SetLength(myid, rowcount);
    SetLength(mydesc, rowcount);
    SetLength(myimg, rowcount);
    SetLength(Stream2, rowcount);

      while not UniTable1.Eof do
      begin
        try
          Stream2[k] := TMemoryStream.Create;
          myid[k] := UniTable1.FieldByName('id').Value;
          Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
          mydesc[k] := UniTable1.FieldByName('description').Value;

         UniTable1.Next;
         inc(k);

        finally
           //Stream2[k].Free;
        end;

      end;

      frxUserDataSet1.RangeEnd := reCount;
      frxUserDataSet1.RangeEndCount := rowcount;
      frxReport1.ShowReport;
      i := 0;
end;

`

However this method is not loading any image to Stream2 array. There is an option to use array of JPEGImage however if JPEGImage array used then it would be problem to display it on frxRaport at

procedure TFrmMain.frxReport1GetValue(const VarName: string; var Value: Variant);

`

Graphic := TJPEGImage.Create;
Graphic.LoadFromStream(Stream2[j]);
TfrxPictureView(frxreport1.FindObject('Picture1')).Picture.Graphic := Graphic;

` Kindly let me know how to do this.


Solution

  • However this method is not loading any image to Stream2 array

    In your current code you are first assigning a newly created TMemoryStream to Stream2[k]:

          Stream2[k] := TMemoryStream.Create;
    

    then you are throwing the TMemoryStream away (creating a memory leak) and replacing it with the blob stream you create:

          Stream2[k] := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
    

    But you never read from the blob stream.

    Here's the while loop rewritten (untested)

    var
      blobstream: TStream;
      Stream2: array of TMemoryStream;
    
      ....
      // read 'id', 'description' and 'image' fields to respective arrays
      while not UniTable1.Eof do
      begin
        myid[k] := UniTable1.FieldByName('id').Value;
        mydesc[k] := UniTable1.FieldByName('description').Value;
    
        blobstream := UniTable1.CreateBlobStream(TBlobField(UniTable1.FieldByName('image')), bmRead);
        try
          Stream2[k] := TMemoryStream.Create;
          Stream2[k].LoadFromStream(blobstream);
        finally
          blobstream.Free;
        end;
    
        UniTable1.Next;
        inc(k);
      end;
    

    Btw, I would recommend to define a record to hold the id, description and image together, and then an array of those records, instead of three separate arrays. Much simpler to manage only one array instead of three.