Recent

Author Topic: [Solved] Show external images in a dbgrid  (Read 538 times)

WimVan

  • New member
  • *
  • Posts: 42
[Solved] Show external images in a dbgrid
« on: December 07, 2018, 02:23:49 pm »
Some one did this already ?
I want to show images in a dbgrid.  The database just owns the imagename and the folder where to find that image on the server.
1) is there a component to show images with correct ratio in the dbgrid.  As I saud, the image is kept outside the database.  Only a reference to the image is hold in two different fields in the database (foto and foto_dir)
2) if there is no component, what must I do  ?  I already tried using the ondrawcoulmcell-event but I lose all tracks ...

Thanks

Wim
« Last Edit: December 10, 2018, 10:08:08 am by WimVan »

mangakissa

  • Hero Member
  • *****
  • Posts: 865
Lazarus 1.84 (32b) / FPC 3.0.4
Windows 10

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #2 on: December 07, 2018, 09:33:17 pm »
I tried that after adapting some properties ...  But result was faulting....
And how to get the value of the foto_dir field when drawing the cell for the foto-field as an image ?

mangakissa

  • Hero Member
  • *****
  • Posts: 865
Re: Show external images in a dbgrid
« Reply #3 on: December 08, 2018, 08:38:28 am »
I don't know when the picture from disk has to be loaded, but you can create a function where the picure will be loaded by stream. TFilestream has a loadfromfile function
Lazarus 1.84 (32b) / FPC 3.0.4
Windows 10

paweld

  • Full Member
  • ***
  • Posts: 173
Re: Show external images in a dbgrid
« Reply #4 on: December 08, 2018, 08:59:08 am »
Code: Pascal  [Select]
  1. uses
  2.   fpimage, fpreadjpeg, fpreadpng, fpreadbmp, fpreadgif, fpreadtiff, fpwritebmp;
  3.  
  4. procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  5.   DataCol: Integer; Column: TColumn; State: TGridDrawState);
  6. var
  7.   bmp: TBitmap;
  8.   image: TFPCustomImage;
  9.   reader: TFPCustomImageReader;
  10.   writer: TFPCustomImageWriter;
  11.   fotostream: TStream;
  12. begin
  13.   if Column.Index=1 then
  14.   begin
  15.     try
  16.       image:=TFPMemoryImage.Create(1, 1);
  17.       writer:=TFPWriterBMP.Create;
  18.       fotostream:=TStream.Create;
  19.       bmp:=TBitmap.Create;
  20.       case ExtractFileExt(ZQuery1.FieldByName('foto').AsString) of
  21.       '.bmp': reader:=TFPReaderBMP.Create;
  22.       '.jpg', '.jpeg': reader:=TFPReaderJPEG.Create;
  23.       '.png': reader:=TFPReaderPNG.Create;
  24.       '.gif': reader:=TFPReaderGif.Create;
  25.       '.tif', '.tiff': reader:=TFPReaderTIFF.Create;
  26.       end;
  27.       if image.LoadFromFile(ZQuery1.FieldByName('foto_dir').AsString+ZQuery1.FieldByName('foto').AsString, reader) then
  28.       begin
  29.         image.SaveToStream(fotostream, writer);
  30.         fotostream.Position:=0;
  31.         bmp.LoadFromStream(fotostream, fotostream.Size);
  32.         DBGrid1.Canvas.StretchDraw(Rect, bmp);
  33.       end;
  34.     finally
  35.       writer.Free;
  36.       image.Free;
  37.       bmp.Free;
  38.       fotostream.Free;
  39.     end;
  40.   end;
  41. end;      
Best regards
paweld

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #5 on: December 09, 2018, 11:42:22 am »
Code: Pascal  [Select]
  1. uses
  2.   fpimage, fpreadjpeg, fpreadpng, fpreadbmp, fpreadgif, fpreadtiff, fpwritebmp;
  3.  
  4. procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  5.   DataCol: Integer; Column: TColumn; State: TGridDrawState);
  6. var
  7.   bmp: TBitmap;
  8.   image: TFPCustomImage;
  9.   reader: TFPCustomImageReader;
  10.   writer: TFPCustomImageWriter;
  11.   fotostream: TStream;
  12. begin
  13.   if Column.Index=1 then
  14.   begin
  15.     try
  16.       image:=TFPMemoryImage.Create(1, 1);
  17.       writer:=TFPWriterBMP.Create;
  18.       fotostream:=TStream.Create;
  19.       bmp:=TBitmap.Create;
  20.       case ExtractFileExt(ZQuery1.FieldByName('foto').AsString) of
  21.       '.bmp': reader:=TFPReaderBMP.Create;
  22.       '.jpg', '.jpeg': reader:=TFPReaderJPEG.Create;
  23.       '.png': reader:=TFPReaderPNG.Create;
  24.       '.gif': reader:=TFPReaderGif.Create;
  25.       '.tif', '.tiff': reader:=TFPReaderTIFF.Create;
  26.       end;
  27.       if image.LoadFromFile(ZQuery1.FieldByName('foto_dir').AsString+ZQuery1.FieldByName('foto').AsString, reader) then
  28.       begin
  29.         image.SaveToStream(fotostream, writer);
  30.         fotostream.Position:=0;
  31.         bmp.LoadFromStream(fotostream, fotostream.Size);
  32.         DBGrid1.Canvas.StretchDraw(Rect, bmp);
  33.       end;
  34.     finally
  35.       writer.Free;
  36.       image.Free;
  37.       bmp.Free;
  38.       fotostream.Free;
  39.     end;
  40.   end;
  41. end;      

Hi,
Thanks,
I tried out this code but I met some errors.
image.LoadFromFile    is a function which returns a boolean if (not) successful, but you may pass just one parameter.

I adapted it, but hen I ran the program, I got a compilation error indicating that Tstream.seek is NOT implemented.

Looking on the forum about this error, some people propose using TMemoryStream

What is the quickest and what consumes less memory ?

Thanks any way

wp

  • Hero Member
  • *****
  • Posts: 5134
Re: Show external images in a dbgrid
« Reply #6 on: December 09, 2018, 01:00:56 pm »
What is the quickest and what consumes less memory ?
You are talking of a "fotostream" and probably have the huge >20 mega pixel photos in mind - this will always be slow even if you use a memory stream because you must read the file and decode the jpeg. Whenever you drag another window over your dbgrid or you drag the grid out of the visible desktop area the required repaint will have to reload the original images.

I'd write the stretchdrawn image to a Bitmap and use this to display the images. A 300x200 uncompressed image (0.24MB) is much smaller than the original many-megapixel file and is already decoded. If the dataset has many rows you should set up a cache for the size-reduced images. Whenever you load an original image stretch-draw it and save the reduced image to a cache folder. When you want to draw a cell you should look whether an already reduced image exists in the cache and load it from there, otherwise you should stretchdraw the image to another cached file. When the dataset scrolls the grid should delete the images attached to inivisible records and load only those visible.

It will be lot of work, though...
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #7 on: December 09, 2018, 04:00:31 pm »
@wp
Correct, but this something I know.  That's why I always keep all photo's outside the database.
In the database resides only a n image-name and a part of the directory where resides the photo.
However, on the harddisk I have 3 similar directory
FolderX\originals\<dir-reference in database>\<photo-name in database>
FolderX\slides\<dir-reference in database>\<photo-name in database>
FolderX\thumbs\<dir-reference in database>\<photo-name in database>

When creating a overview in a grid, I use thumb-presentation
When creating a full-screen-image I uses the slide-option
When looking to the reall image (can be 36 MP) I use the original option.

Tho construct the real path, I have just to choose between originals, slides or thumbs.
This work extremely quick.
Of course, the select has his limitation where I only permit a max of 100 images...

Ok, all photo's are kept 3 times.  One with full size, one with a 1024-768-base and one with 250-250-base.
So we talk about 35 MP or higher, ¹200Kb and ±6Kb
For the moment I own about 130.000 images and I once wrote a program to maintain, order, tag, ... this with PHP and HTML.  Program is still used and runs now for more than 15 years ...  Now I would like to have an exe that runs without HTML, PHP.

But thanks for the useful info
« Last Edit: December 09, 2018, 04:39:14 pm by WimVan »

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #8 on: December 09, 2018, 09:09:10 pm »
Next code is running finally.
I used TImage because it is more versatile and some properties are usefull

Code: Pascal  [Select]
  1. procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  2.   DataCol: Integer; Column: TColumn; State: TGridDrawState);
  3. var
  4.   image : TImage;
  5.   foto : string;
  6. begin
  7.   if Column.Index=2 then
  8.   begin
  9.     image := TImage.Create(Self);
  10.     try
  11.       foto := DIR_SLIDE+SQLQuery1.FieldByName('foto_dir').AsString+'\'+SQLQuery1.FieldByName('foto').AsString;
  12.       case ExtractFileExt(foto) of
  13.       '.bmp': image.Picture.Bitmap.LoadFromFile(foto);
  14.       '.jpg', '.jpeg': image.Picture.Jpeg.LoadFromFile(foto);
  15.       '.png': image.Picture.PNG.LoadFromFile(foto);
  16.       end;
  17.       DBGrid1.Canvas.Draw(Rect.left, Rect.Top, image.Picture.Graphic);
  18.     finally
  19.       image.Free;
  20.     end;
  21.   end;
  22. end;
  23.  

Next to do is center the image, resize ... but Timage-properties does a lot of these

wp

  • Hero Member
  • *****
  • Posts: 5134
Re: Show external images in a dbgrid
« Reply #9 on: December 09, 2018, 09:50:23 pm »
You don't have to check the extension. Image.Picture.LoadFromFile is all that you need, it checks the file format and creates the correct bitmap class.

And you even don't need a TImage, you can create a TPicture independently:
Code: Pascal  [Select]
  1. procedure TForm1.DBGrid1DrawColumnCell(Sender: TObject; const Rect: TRect;
  2.   DataCol: Integer; Column: TColumn; State: TGridDrawState);
  3. var
  4.   pic: TPicture;
  5.   foto : string;
  6. begin
  7.   if Column.Index=2 then
  8.   begin
  9.     pic := TPicture.Create;
  10.     try
  11.       foto := DIR_SLIDE+SQLQuery1.FieldByName('foto_dir').AsString+'\'+SQLQuery1.FieldByName('foto').AsString;
  12.       pic.LoadFromFile(foto);
  13.       DBGrid1.Canvas.Draw(Rect.left, Rect.Top, pic);
  14.     finally
  15.       pic.Free;
  16.     end;
  17.   end;
  18. end;

« Last Edit: December 09, 2018, 09:53:33 pm by wp »
Lazarus trunk / fpc 3.0.4 / all 32-bit on Win-10

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #10 on: December 09, 2018, 10:07:27 pm »
Correct, but then I do not heve properties like strech, autosize, ... and these I'm tending to use.

mangakissa

  • Hero Member
  • *****
  • Posts: 865
Re: Show external images in a dbgrid
« Reply #11 on: December 10, 2018, 08:40:35 am »
Quote
Correct, but then I do not heve properties like strech, autosize, ... and these I'm tending to use.
Code: [Select]
DBGrid1.Canvas.Draw(Rect.left, Rect.Top, pic);
Why stretching if this procedure draws the picture in the size of the painted row?
Lazarus 1.84 (32b) / FPC 3.0.4
Windows 10

WimVan

  • New member
  • *
  • Posts: 42
Re: Show external images in a dbgrid
« Reply #12 on: December 10, 2018, 10:07:13 am »
Quote
Correct, but then I do not heve properties like strech, autosize, ... and these I'm tending to use.
Code: [Select]
DBGrid1.Canvas.Draw(Rect.left, Rect.Top, pic);
Why stretching if this procedure draws the picture in the size of the painted row?

Also correct, but I just wrote that there are some properties that can be very usefull.
I didn't used them here.  It just serves as how I can show an image in the DBGrid