Recent

Author Topic: How to check if image format is supported?  (Read 3984 times)

TomTom

  • Full Member
  • ***
  • Posts: 170
How to check if image format is supported?
« on: February 17, 2019, 03:53:36 pm »
Hi
I'm writing simple image viewer. My form contains StringGrid filled with file paths (not only image files and I want that).
On StringGrid.OnSelection I have code that :
- checks if file from stringgrid exists
- check if thumbnail was generated from that file
- if there is no thumbnail for that file then it is generated
- if there is thumbnail it is being drawn on some canvas...

Ofcourse my program is crashing when user selects row of StringGrid which contains path to file which is not supported and never will (i.e any non-image file).
How can I check if selected file is supported by TPicture? I could check if file extension is jpg/tif/png etc... but is there way something like this

IF selected_file IS NOT IN supported_file_formats_of_TPicture THEN do_nothing ELSE create_thumbnail;   

Handoko

  • Hero Member
  • *****
  • Posts: 5130
  • My goal: build my own game engine using Lazarus
Re: How to check if image format is supported?
« Reply #1 on: February 17, 2019, 04:45:03 pm »
Maybe you can use exception block:
https://freepascal.org/docs-html/ref/refch17.html

If the thumbnail creation fails in the block, the exception will be caught and destroyed, so your program ignore it (like nothing happened).

FYI, you should test the binary directly (not from the IDE) because Lazarus will show you a notification if an exception occurs even it has been caught and destroyed.

TomTom

  • Full Member
  • ***
  • Posts: 170
Re: How to check if image format is supported?
« Reply #2 on: February 17, 2019, 05:00:58 pm »
Thank You Handoko. Especially for that advice to test not from IDE ;P.. It will save me a lot of trouble :P
« Last Edit: February 17, 2019, 05:03:56 pm by TomTom »

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: How to check if image format is supported?
« Reply #3 on: February 17, 2019, 05:51:33 pm »
I think exceptions should be avoided because they are slow and interrupt the work in the IDE.

Looking into the sources of the graphics classes you'll see that all the LCL image formats inherit from TFPImageBitmap, and this class has a class function IsStreamFormatSupported which is virtual and implemented by each image format reader to check whether this particular format matches the passed stream.  So, you only have to load your image into into a stream and pass that to this function for the image class that you want to test. Something like this:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.Button1Click(Sender: TObject);
  2. var
  3.   s : TStream;
  4. begin
  5.   s := TFileStream.Create(Edit1.Text, fmOpenRead);
  6.   try
  7.     if TBitmap.IsStreamFormatSupported(s) then
  8.       Caption := 'TBitmap'
  9.     else
  10.     if TJpegImage.IsStreamFormatSupported(s) then
  11.       Caption := 'TJpegImage'
  12.     else
  13.     if TPortableNetworkGraphic.IsStreamFormatSupported(s) then
  14.       Caption := 'TPortableNetworkGraphic'
  15.     else
  16.       Caption := 'Format not detected';
  17.   finally
  18.     s.Free;
  19.   end;
  20. end;

Or a bit more general - it returns the class of the image in the stream:
Code: Pascal  [Select][+][-]
  1. function GetImageClass(S: TStream): TFPImageBitmapClass;
  2. const
  3.   CLASS_LIST: array[0..4] of TFPImageBitmapClass = (
  4.     TBitmap, TJpegImage, TPortableNetworkGraphic, TPixMap, TTiffImage);
  5. var
  6.   c: TFPImageBitmapClass;
  7. begin
  8.   for c in CLASS_LIST do
  9.     if c.IsStreamFormatSupported(S) then begin
  10.       Result := c;
  11.       exit;
  12.     end;
  13.   Result := nil;
  14. end;  

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: How to check if image format is supported?
« Reply #4 on: February 17, 2019, 07:15:13 pm »
You can also use TPicture.FindGraphicClassWithFileExt() but beware that, contrary to what is stated in the docs, it's not a class method so you need an instance of the class.

For example, you could make something like:

Code: Pascal  [Select][+][-]
  1. function IsValidGraphic(const AnExt: String): Boolean;
  2. begin
  3.   with TPicture.Create do
  4.   try
  5.     Result := FindGraphicClassWithFileExt(AnExt, False) <> nil;
  6.   finally
  7.     Free;
  8.   end;
  9. end;

and call it through:
Code: Pascal  [Select][+][-]
  1. if IsValidGraphic(ExtractFileExtension(AFilename)) then
  2.   {whatever you want to do when it's a graphic}
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: How to check if image format is supported?
« Reply #5 on: February 17, 2019, 07:40:52 pm »
You can also use TPicture.FindGraphicClassWithFileExt() but beware that, contrary to what is stated in the docs, it's not a class method so you need an instance of the class.
This is no longer true for Laz2.0+:
Code: Pascal  [Select][+][-]
  1. type
  2.   TPicture = class(TPersistent)  
  3.   [...]
  4.     class function FindGraphicClassWithFileExt(const Ext: string;
  5.       ExceptionOnNotFound: boolean = true): TGraphicClass;  

lucamar

  • Hero Member
  • *****
  • Posts: 4219
Re: How to check if image format is supported?
« Reply #6 on: February 17, 2019, 08:22:43 pm »
[...] it's not a class method [...]
This is no longer true for Laz2.0+:

Ah, nice! Then in Lazarus 2.0+ you can simply do:
Code: Pascal  [Select][+][-]
  1. function IsValidGraphic(const AnExt: String): Boolean;
  2. begin
  3.   Result := TPicture.FindGraphicClassWithFileExt(AnExt, False) <> Nil;
  4. end;
Turbo Pascal 3 CP/M - Amstrad PCW 8256 (512 KB !!!) :P
Lazarus/FPC 2.0.8/3.0.4 & 2.0.12/3.2.0 - 32/64 bits on:
(K|L|X)Ubuntu 12..18, Windows XP, 7, 10 and various DOSes.

local-vision

  • New Member
  • *
  • Posts: 48
Re: How to check if image format is supported?
« Reply #7 on: January 05, 2024, 06:29:41 am »
This answers the topic question. It tests if the file ext matches the supported image file formats.

But what about actually testing if the file is an actual image file and not, let say, a text file with a .bmp extension?

Is there any means to do this or is it better to just use a try except block?

Thanks

Zvoni

  • Hero Member
  • *****
  • Posts: 2317
Re: How to check if image format is supported?
« Reply #8 on: January 05, 2024, 08:07:05 am »
This answers the topic question. It tests if the file ext matches the supported image file formats.

But what about actually testing if the file is an actual image file and not, let say, a text file with a .bmp extension?

Is there any means to do this or is it better to just use a try except block?

Thanks
Each "Image"-Format has a specific header. You could open the file, and check for the Headers.

for your example "textfile with bmp-Extension":
You would expect "Bitmap"-Format
"Bitmap"-Format Header = 0x42 0x4D (https://en.wikipedia.org/wiki/BMP_file_format)
If the first 2 Bytes are 0x42 0x4D then it's a valid Bitmap, if no.....

OTOH, if your Textfile actually starts with exactly those values you're back at square one.

Bottom Line: I don't think you can avoid exception-handling (try/Except)
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: How to check if image format is supported?
« Reply #9 on: January 05, 2024, 09:28:48 am »
But what about actually testing if the file is an actual image file and not, let say, a text file with a .bmp extension?

Is there any means to do this or is it better to just use a try except block?
Why don't you do what I wrote in reply #3? This is exactly for what you are asking. And Zvoni: no exception needed this way.

Zvoni

  • Hero Member
  • *****
  • Posts: 2317
Re: How to check if image format is supported?
« Reply #10 on: January 05, 2024, 01:13:48 pm »
But what about actually testing if the file is an actual image file and not, let say, a text file with a .bmp extension?

Is there any means to do this or is it better to just use a try except block?
Why don't you do what I wrote in reply #3? This is exactly for what you are asking. And Zvoni: no exception needed this way.
wp, yeah, i saw your answer, but essentially it boils down to the same thing:
he would have to implement for each format the "IsStreamFormatSupported"-Check.
Whether using your approach (nice btw.) or doing everything by hand as in mine.
And with "exception"-handling i don't neccessarily mean try/except (even if i quoted it), but to "prepare" for unforseen stuff
One System to rule them all, One Code to find them,
One IDE to bring them all, and to the Framework bind them,
in the Land of Redmond, where the Windows lie
---------------------------------------------------------------------
Code is like a joke: If you have to explain it, it's bad

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: How to check if image format is supported?
« Reply #11 on: January 05, 2024, 06:18:23 pm »
If the first 2 Bytes are 0x42 0x4D then it's a valid Bitmap, if no.....
Well, some more checks are needed.

An excerpt from a unit of mine that tries to determine what picture format a given file is:
Code: Pascal  [Select][+][-]
  1. function MaybeBmp(St: TStream; ChunkSize: Integer; out Width, Height: DWord): TImageFormat;
  2. var
  3.   BFH: TBitmapFileHeader;
  4.   BInfo: TBitmapInfo;
  5.   IDStr: String;
  6. begin
  7.   Result := ifUnknown;
  8.   if (ChunkSize < (SizeOf(TBitmapFileHeader) + SizeOf(TBitmapInfo))) then Exit;
  9.   St.Position := 0;
  10.   St.ReadBuffer(BFH, Sizeof(TBitmapFileHeader));
  11.   St.ReadBuffer(BInfo, SizeOf(TBitmapInfo));
  12.   BFH.ID := LeToN(BFH.ID);
  13.   IDStr := Char(Lo(BFH.ID)) + Char(Hi(BFH.ID));
  14.   {$ifdef DebugPicsLib}
  15.   if IsConsole then writeln('IDStr = ',idstr);
  16.   if IsConsole then writeln('BInfo.BitmapHeaderSize = $',IntToHex(BInfo.BitmapHeaderSize,2));
  17.   if IsConsole then writeln('BInfo.BitsPerPixel = ',BInfo.BitsPerPixel);
  18.   {$endif}
  19.   BInfo.BitmapHeaderSize := LeToN(BInfo.BitmapHeaderSize);
  20.   BInfo.BitsPerPixel := LeToN(BInfo.BitsPerPixel);
  21.   if ((IDStr = 'BM') or (IDStr = 'BA')) and
  22.      (BInfo.BitmapHeaderSize in [$28,$0c,$f0]) and
  23.      (BInfo.BitsPerPixel in [1,4,8,16,24,32])then
  24.   begin
  25.     Width := LeToN(BInfo.Width);
  26.     Height := LeToN(BInfo.Height);
  27.     Result := ifBmp;
  28.   end;
  29.   {$ifdef DebugPicsLib}
  30.   if IsConsole then writeln('MaybeBmp: Result = ',Result);
  31.   {$endif}
  32. end;
I have similar functions for PNG, GIF and JPEG.

Bart

wp

  • Hero Member
  • *****
  • Posts: 11854
Re: How to check if image format is supported?
« Reply #12 on: January 05, 2024, 06:42:49 pm »
he would have to implement for each format the "IsStreamFormatSupported"-Check.
No, because every graphic format supported by FPC already has it. Doing it manually is only required when you want to avoid using the LCL (and FCL-Image).

If the first 2 Bytes are 0x42 0x4D then it's a valid Bitmap, if no.....
Well, some more checks are needed.
Basically yes, because the "magic header" 'BM' of bitmap files might exist in a text file as well, although it is not a very common combination of letters. But even the TFPReaderBMP, which is the base of TBitmap reading, is satisfied when it sees the 'BM' only. Bart, maybe you should write a feature request to extend TFPReaderBMP.InternalCheck (in unit fpreadbmp) in your way?

Bart

  • Hero Member
  • *****
  • Posts: 5275
    • Bart en Mariska's Webstek
Re: How to check if image format is supported?
« Reply #13 on: January 05, 2024, 08:02:54 pm »
Bart, maybe you should write a feature request to extend TFPReaderBMP.InternalCheck (in unit fpreadbmp) in your way?
I filed a bugreport, so let's see what the devels say about this.

Bart

local-vision

  • New Member
  • *
  • Posts: 48
Re: How to check if image format is supported?
« Reply #14 on: January 06, 2024, 01:27:40 am »
Thanks for the helpful and concise responses. Again a testament to the dedicated Lazarus community.

I expect that Wirth was proud to his last day of the community involvement that surrounded his ever expanding work from yesteryear.


My query is out of concern and curiosity and less about specific application.

An image file tester would be of some value in my view. File testing in general is. Is that file what it claims it is...

Opening and reading the entire file to determine if it is what it claims to be defeats the idea of a tester.

While simply reading the file ext is a too unreliable way to test.

Each image file has its own inherent properties that would together indicate the probability that the file is actually what it claims to be.

We then have a mechanism to determine what type of file this might or might not be.

As such, expanding on the tactic first suggested by Zvoni and subsequent input by wp and Bart seems like the way to go.

"function MaybeBmp" interesting stuff Bart...

 

TinyPortal © 2005-2018