AWARE [SYSTEMS] Imaging expertise for the Delphi developer
AWare Systems, Imaging expertise for the Delphi developer, Home TechTalks / VCL TGraphic basics
AWare Systems on-line

Home
Custom development
Imaging
TechTalks
    Format from data
    Tiling versus banding
    VCL TGraphic basics
    Unused color
Company
Links

Languages

  English version
  Nederlandse versie

Contact

Information: info@awaresystems.be
Helpdesk: support@awaresystems.be
Sales: sales@awaresystems.be



Valid HTML 4.01!



What goes in a Delphi VCL TGraphic, TPicture, TImage, and how to convert between graphic file formats?

> What's in a Delphi VCL TGraphic, TPicture, TImage, anyway? When to use what?
> And how should I use them to convert between graphic file formats?

There seems to be a lot of confusion about this. The actual intention of the VCL TGraphic design is poorly understood, design-wise corrupted by the non-fitting TBitmap, badly documented, and very often confused with the functionality of a TImage. It is nevertheless a very fine design.

In short (and not entirely absolutely correct):

  • A TGraphic knows how to maintain a raster and how to draw it on a drawing surface (TCanvas, or DC on the Windows level)
    • A descendant of TGraphic, like TJpegImage or TBitmap for example, may be designed to also know how to read and write a very specific file format. Thus, a TJpegImage knows how to maintain a raster and draw it, but it also knows how to read that raster from a jpeg file, or how to write it to file compliant with the JPEG file format specification.
    • A Delphi TBitmap is multi-purpose in that it covers the above functionality, but is also *the* graphic object on the windows level. Thus, it's also a more or less file format independent thingy that you use for holding temporary buffers and such.
    • A TPicture seems similar to TGraphic. But it is not at all like a TJpegImage or TBitmap. Instead of even directly managing a raster, it manages a TGraphic, of any type. Thus, it is able to e.g. add the 'graphic type selection' functionality in e.g. a LoadFromFile method, since it can detect the file extension from the file name, deduce what is the proper TGraphic type, start managing such a descendant TGraphic, and delegate the real Loading to that owned TGraphic.
  • A Delphi TImage contains and manages a TPicture. It's not intended to replace the functionality of a TPicture, but to complement it with rendering in a UI context. Thus, managing an invisible TImage simply to hold a TPicture/TGraphic, for instance, is nonsense.

(The above is not entirely correct, in that a TGraphic doesn't even know how to maintain and draw a raster, really. Even this functionality is covered in the descendant objects. That's good design because it allows for e.g. multipage or video TGraphic classes, and for tile array rasters that withstand the big image problem and such... But it confuses the point I tried to make, and there aren't that many multipage or video TGraphics around, so...)

A common application of this object oriented design is converting between graphic file formats. Suppose you need to convert a JPEG file to a BMP file, for example. This involves reading the JPEG file into a raster, and subsequently writing out that raster to a BMP file. The first part of this task is covered by the TJpegImage object, since this one knows how to read and decode a JPEG file. The raster object, managed by this TJpegImage, subsequently needs to be transfered to a TBitmap object. This TBitmap object, in turn, is able to encode and write out the BMP file.

Eliminating all exception handling and such, for clearity, this amounts to:

procedure ConvertJpegFileToBitmapFile(const SourceFilename, DestinationFilename: String);

var

jpeg: TJpegImage;

bmp: TBitmap;

begin

jpeg := TJpegImage.Create;

jpeg.LoadFromFile(SourceFilename);

bmp := TBitmap.Create;

bmp.Assign(jpeg);

bmp.SaveToFile(DestinationFilename);

bmp.Free;

jpeg.Free;

end;

Now you see where the Assign comes in. Internally, these TJpegImage and TBitmap objects are supposed to maintain rasters with usage counters. The Assign statement, officially, copies the raster content of the jpeg object into the bmp object. Underneath, this does *not* involve creating a second raster and copying the pixel data, but boils down to sharing the raster object and incrementing its usage counter, eliminating the need for duplicating memory.

Please drop us a line if you wish to be kept informed about changes and additions to this page.