PNG Graphics with Delphi and Kylix

Index

Introduction

As my web page devoted to web graphics suggests, I am a fan of the PNG graphics format. PNG is a compressed graphics format, so PNG images take up less disk space than BMP or TIFF images (there are actually compressed variations of both these formats, but most of these images are uncompressed and their compression schemes do not shrink most images very much). Unlike the JPEG format, PNG is lossless, so the images do not compromise quality. Unlike the GIF format, PNG has no licensing issues and is able to compress 24-bit color images (GIF images can not have more than 256 distinct colors).

It should be noted that for photographs and other images with gradually changing colors, PNG will not make files that are as small as JPEG. The JPEG format is well suited for digital photography. However, for images where precision is required or where there are large regions of the same color [e.g. line art], PNG is an excellent choice Again, my web graphics page discusses the relative merits of these formats.

If PNG does have a weakness, it is compression speed. It takes quite a while to compress a PNG graphic (though decompressing the image is very quick). However, as computers get faster, this is becoming less of an issue. One other problem is that PNG is not yet as widely available as JPEG, GIF, BMP and TIF reading software. However, all modern web browsers, word processors, and painting packages now support PNG.

PNG with Delphi

Update: since I wrote this page, Gustavo Daud has released a new version of his TPNGimage software. To download his code and demos, visit his Sourceforge web site.

Adding support for PNG in programs written in Delphi has traditionally been difficult. Most solutions require the developer to distribute a separate DLL file along with their program. DLLs are useful for allowing multiple programs to use the same code, but they can make distribution a bit challenging.

On the other hand, Gustavo Daud has written has created a free and fast native Delphi component called 'TPNGImage'. This software makes it easy to read and write PNG images. The code is compiled with your applications, so you do not need to distribute a separate DLL.

Gustavo's code is used by a number of useful Open Source projects. My own sample project is very simple, allowing programmers who are unfamiliar with this software to understand how to view and save PNG images. The PNGproj application offers drag and drop support for BMP, JPEG and PNG images. You can also save images to each of these formats.

My software also demonstrates how different PNG 'filters' can influence the compressed size of a file. The 'filter' is a way of predicting the color of a pixel during compression For example, an 'up' filter predicts that a pixel will be similar to the pixel directly above it. The closer a pixel is to the predicted value, the better the image can be compressed. PNG has 5 filters: None, Sub, Up, Average, and Paeth. It should be pointed out that all of these filters are 'lossless' - the image quality is not influenced by your choice of a filter, only the file size. Some images will compress well with one filter, while others compress better with another. In my experience, 'none' is good for line art, while the 'Sub' filter works well for photographic images My software reports the disk space required by each compression method, and can also automatically save your file with the most efficient method.

My software is available as source code (with the Gustavo's TPNGimage unit, shift+click here), or as a compiled application (shift+click here). Gustavo's implementation is very easy to use. Other applications are easily able to view images created with this software, and it is able to read virtually every PNG I have seen.

PNG with Kylix

Kylix applications (and CLX applications written in Delphi 6) natively support PNG format images. However, this feature is not well documented (Mohamed Helal taught me this trick). To read and write PNG as well as BMP and JPEG format images, do the following:

  1. Add 'QT' to the 'uses' section of your main form.
  2. On the FormCreate method of your main form, include the lines
       Image1.Picture.RegisterFileFormat('jpg; *.jpeg','JPEG',TBitmap);
       OpenDialog1.Filter := GraphicFilter(TGraphic);
       SaveDialog1.Filter := GraphicFilter(TGraphic);
  3. Loading a bitmap is simple: QT will automatically detect the format of the image and convert it correctly:
       Image1.Picture.Bitmap.LoadFromFile(OpenDialog1.Filename);
  4. Saving an image is a bit trickier. The Image1.Picture.Bitmap.SaveFile method does not work: it always saves images as BMP format images, regardless of the specified extension.
    procedure TMainForm.SaveClick (Sender: TObject);
    var
       lWideStr: WideString;
    begin
        if Image1.Picture.Graphic = nil then exit;//no image loaded
       SaveDialog1.Filter := GraphicFilter(TGraphic); //if this line is not in your FormCreate
        if not SaveDialog1.execute then exit;
        lWideStr := SaveDialog1.Filename;
        QPixMap_save (Image1.Picture.Bitmap.Handle,@lWideStr,PChar('PNG'));
        //for JPEG: QPixMap_save (Image1.Picture.Bitmap.Handle,@lWideStr,PChar('JPEG'), 75);
        //Note: you can pass a 'Quality' level for JPEG: 1..100, 75 is about right
          //for details on JPEG quality, see http://www.efg2.com/Lab/Graphics/BMPJPG.htm
        //for BMP: QPixMap_save (Image1.Picture.Bitmap.Handle,@lWideStr,PChar('BMP'));

    end;
      Image1.Picture.Bitmap.SaveToFile(SaveDialog1.Filename);
    end;

Technical Links: