Search code examples
imagedelphijpegdelphi-7graphics32

Where Delphi TFileFormatsList gets it members and is this dependent on installed third party libraries?


I am experiencing that Delphi's TImage component is very poor. I am working with various Delphi versions starting from Delphi 6 (2000 edition, we still have some projects on it) and ending with Tokyo, Alexandria. TImage has poor support for files beyond ico/bmp/jpg, it has no EXIF auto-rotation feature, and it has no resampling/interpolation.

I tried to find open source replacement using Graphics32's TImage32 and I have installed it. But I am experiencing multiple problems:

  • Delphi 6 compiled program with TImage32 can load png files on Windows 10, but the same exe reports 'Unknown file extension (.png)' on Windows XP (yes, we still use them).

  • There are some jpg files that can be opened in image editors without problems, but loading them in TImage32 reports 'JPEG error #52'.

  • I observed even more strange things: after installing Graphics32 components in my Delphi 6, the following builds can not load jpg files into VCL's TImage! And reports 'Unknown file extension (.jpg)'.

OK, so - lot of problems, possibly too many for one question. But my question is about the core issue that underlies all these problems: I see this VCL code:

procedure TPicture.LoadFromFile(const Filename: string);
var
  Ext: string;
  NewGraphic: TGraphic;
  GraphicClass: TGraphicClass;
begin
  Ext := ExtractFileExt(Filename);
  Delete(Ext, 1, 1);
  GraphicClass := FileFormats.FindExt(Ext);
  if GraphicClass = nil then
    raise EInvalidGraphic.CreateFmt(SUnknownExtension, [Ext]);

  NewGraphic := GraphicClass.Create;
  try
    NewGraphic.OnProgress := Progress;
    NewGraphic.LoadFromFile(Filename);
  except
    NewGraphic.Free;
    raise;
  end;
  FGraphic.Free;
  FGraphic := NewGraphic;
  FGraphic.OnChange := Changed;
  Changed(Self);
end;

Which is being executed upon loading an image, both into TImage (from VCL) and TImage32 (from Graphics32), and the core thing is:

GraphicClass := FileFormats.FindExt(Ext);
if GraphicClass = nil then
  raise EInvalidGraphic.CreateFmt(SUnknownExtension, [Ext]);

I guess - there can be 2 problems:

  1. the graphic class simply can not be found and loaded. Maybe Windows 10 has some libraries for png files, and the png graphics class is loaded into FileFormats, but maybe Windows XP has no such library, and that is why my exe can not load this graphics class when the exe is being run on Windows XP.

  2. there can be multiple implementations for one format, e.g. for jpg. That is why my programs could load a jpg file into TImage before installing Graphics32, and Graphics32 may have added another implementation (or may have corrupted or removed it?), and that is why my TImage cannot load a jpg into TImage after installation of Graphics32.

So - all is boiling down to the method, how is the Graphics.FileFormats list being populated?

I see VCL Graphics.pas code:

constructor TFileFormatsList.Create;
begin
  inherited Create;
  Add('wmf', SVMetafiles, 0, TMetafile);
  Add('emf', SVEnhMetafiles, 0, TMetafile);
  Add('ico', SVIcons, 0, TIcon);
  Add('bmp', SVBitmaps, 0, TBitmap);
end;

And it has no jpg file. So - I guess, that FileFormats is created with the default 4 formats, and then some other libraries somehow can add entries to this list?

I don't know how this is happening, and this is the core of my question - how does the FileFormats list get additional entries so that these entries can be used by TImage and TImage32 (Graphics32)? Are these additional entries dependent on the existence of some DLLs, libraries, possibly registered Windows COM libraries for the additional formats?

My understanding is that something has gone wrong with the population of FileFormats on my development machine.

Progress update added:

  • I should add jpeg to the uses clause, and then TImage can load jpg files as well. So - uses entries determine that graphic formats are loaded. So - this is one mechanism that determines the available graphic formats.

  • It appeared that my 'JPEG error #52' 'jpg files' were png files generically, and so the error message was correct.

But I am still seeking solution why my Delphi 6 program with TImage32 can load png files on Window 10, but reports 'Unknown file format (.png)' on Windows XP.

After finding the entire spectrum of populating Graphics.FileFormats, I hope to write an answer, if there will not be one at that time.


Solution

  • So, it appeared, that adding units to the uses clause solve the problem. I have added:

    • jpeg to support jpg and jpeg files.

    • cxGraphics to support png files (fortunately, I had DevExpress Suite installed, and migrated to Delphi 6, and cxGraphics was intended for its TcxImageView component, which, while supporting many different file formats, did have support for resampling/interpolation and EXIF auto-rotation. I am reading that as of 2023/2024, DevExpress has added support for EXIF auto-rotation, and maybe there is support for resampling in the latest versions as well).

    Has Graphics32 some units which can be added to uses clause instead of commercial cxGraphics? To answer that, I did a WinGrep search over 'graphics32 master' for RegisterFileFormat() and it returned nothing.

    So - one should look at other third party units for supporting the more exotic file formats (png, tiff, webp; in fact my version of cxGraphics supports png only from this trio), but Graphics32 is good for resampling and for fast EXIF rotation (if EXIF orientation is determined by some other methods, e.g. by reading EXIF information using GDI+ libraries).

    So - this explains support for file formats, and solve all my issues.