Search code examples
delphiblobfirebirdfiredactimage

How to load an image from Firebird Database as Blob to TImage in Delphi with FireDAC?


I've searched on many places on internet but I couldn't find a proper solution yet. Most of the examples uses other component or aims direct saving etc.

My problem is that ; I have 2 database on server one is holding Products' info (stock code, name, prices etc.), other is images of products (can be jpeg, png, gif). There is a unique value on both databases to pair products and images (prod_id).

I've put 2 TFDConnection, 2 TFDQuery and 1 TDataSource components on the form, I am fetching data from info database and load these data into a StringGrid via TDataSource, TFDConnection, TFDQuery and other TFDConnection and TFDQuery components to connect images database.

And I would like to do that; When I click a row on StringGrid, let program get prod_id value of selected row (no problem until there) and then search on images' database if there is a prod_id value and image as blob (FILEDATA field) show this image on TImage control.

Is there any way to do this with FireDAC components? Or should i follow another way? Thanks.


Solution

  • If you look in your Delphi samples folder, you should find an example under the LiveBindings folder called BindGridLinkVCLProject (maybe you're using this already).

    This shows how to use live bindings to populate a StringGrid from a TDataSet and how to also use it to load an image stored in a database, based on the current record show in the StringGrid.

    It uses a ClientDataSet loaded with the data of the standard (Borland) Biolife database (aka FishFacts). I have checked and you can replace the ClientDataSet with a FireDAC one (I used a TFDMemTable, because the sample data includes the Biolife DB in its format, too). As Ken White said in a comment, it shouldn't make any difference that you are using a Firebird database (except to which FireDAC dataset type you use, of course).

    I also checked that you can use a second FireDAC dataset to do a look-up to retrieve the image and load that into a TImage too. Following shows how.

    In the BindGridLinkVCLProject demo project, the Graphic column of the data contains the picture of the fish and this gets displayed in a TImage via Livebinding.

    It's easy to adapt this demo project to retrieve the image from a different TDataSet (though in what I describe below, we simply use a second copy of the Biolife dataset) and use FireDAC datasets instead of ClientDataSets. (Obviously this is a artificial example because the Biolife data already has the image data in it, but the following is to show that even with live bindings it is quite easy to retrieve an image from another dataset if you need to.)

    Try the following:

    • Make a copy of the project and its GridLinkFormUit1.Pas file.

    • Replace ClientDataSet1 with an FDMemTable.

    • Point DataSource1 and BindSourceDB1 at FDMemTable1.

    • Load FDMemTable1 (right-click on it in the IDE) from the Biolife.Fds file in the Samples Data folder.

    At this point, StringGridWithBindColumns should show the Biolife data and the ImageWithHandler TImage should show the picture of the current fish. Now,

    • Double-click BindingList1 and, in the pop-up, delete the Bind Component for ImageWithHandler. We'll add this to a separate BindingList below.

    • Add a second FDMemTable to the form and load it with the same data as FDMemTable1.

    • Add a second DataSource and BindingList to the form. Point DataSource2 at FDMemTable2.

    • Then, double-click BindingList2, and use the editor to add a new binding between the Graphic field of FDMemTable2 and the ImageWithHandler TImage (see DFM below for how to wire this up. The Bindings editor should automstically create BindSourceDB2 and you need to set its DataSet and DataSource properties to FDMemTable2 and DataSource2.

    Then, add the following code to the form's unit, compile and run:

      TGridLinkForm1 = class(TForm)
        [...]
      public
        { Public declarations }
        DataFileName : String;
      end;
    
    
    procedure TGridLinkForm1.FormCreate(Sender: TObject);
    begin
      DataFileName := 'D:\xe8\samples\Data\Biolife.Fds';
      if not FDMemTable2.Active then
        FDMemTable2.LoadFromFile(DataFileName);
      if not FDMemTable1.Active then
        FDMemTable1.LoadFromFile(DataFileName);
    end;
    
    procedure TGridLinkForm1.FDMemTable1AfterScroll(DataSet: TDataSet);
    var
      SpeciesNo : Double;
    begin
      SpeciesNo := FDMemTable1.FieldByName('Species No').AsFloat;
      if not FDMemTable2.Locate('Species No', SpeciesNo, []) then
        raise Exception.CreateFmt('SpeciesNo %n not found in %s', [SpeciesNo, FDMemTable2.Name]);
    end;
    

    DFM extract:

      object FDMemTable2: TFDMemTable
        FetchOptions.AssignedValues = [evMode]
        FetchOptions.Mode = fmAll
        ResourceOptions.AssignedValues = [rvPersistent, rvSilentMode]
        ResourceOptions.Persistent = True
        ResourceOptions.SilentMode = True
        UpdateOptions.AssignedValues = [uvCheckRequired]
        UpdateOptions.CheckRequired = False
        Left = 24
        Top = 392
      end
      object DataSource2: TDataSource
        DataSet = FDMemTable2
        Left = 88
        Top = 392
      end
      object BindSourceDB2: TBindSourceDB
        DataSource = DataSource2
        ScopeMappings = <>
        Left = 236
        Top = 392
      end
      object BindingsList2: TBindingsList
        Methods = <>
        OutputConverters = <>
        Left = 152
        Top = 392
        object LinkControlToField1: TLinkControlToField
          Category = 'Quick Bindings'
          DataSource = BindSourceDB2
          FieldName = 'Graphic'
          Control = ImageWithHandler
          Track = False
        end
      end