Bitmap to PNG/JPEG/JPG in Delphi / C++Builder

In FireMonkey, Bitmap is the common currency for working with images. If you want to send an image via Stream using LiveBindings or want to save an Image to disk or into a database on a device with limited storage however, they are quite large.

Thankfully FireMonkey has a really easy to use CodecManager that allows you to SaveToFile or SaveToStream and convert to PNG or JPG across all platforms (which are vastly smaller in size).

SaveToFile

Creating a PNG, JPG/JPEG is as simple as calling the Bitmap.SaveToFile with the correct file extension. This works really well with even more extensions supported.

Personally I would use PNG as the JPG formats are around the same size on some test I’ve run, but produce a better quality of image, especially when grabbing screenshots.

SaveToStream and TBitmapCodecManager

Bitmap.SaveToStream doesn’t expose the CodexManager in the same way as it is available automatically with the SaveToFile option so takes a little more work to get a compressed image into the memory stream.

This is done using the TBitmapCodecManager class. A simple screen test has gone from over 1mb as a bitmap to around 6kb when saved to PNG using this approach.

The following code is an example using two image viewers (and a few save to files to help demonstrate the difference in file size). The key part is the TBitmapSurface and TBitmapCodecManager.

procedure TForm1.Button1Click(Sender: TObject);
var
  Stream: TMemoryStream;
  Surf: TBitmapSurface;
  aFile : string;
begin
  ImageViewer1.Bitmap :=
    TabControl1.MakeScreenshot;

  // Comparison save file as BMP 
  aFile := 'c:\test\myImage';
  ImageViewer1.Bitmap.SaveToFile(aFile+'.bmp');
  Stream := TMemoryStream.Create;
  try
    Stream.Position := 0;
    Surf := TBitmapSurface.Create;
    try
      Surf.Assign(ImageViewer1.Bitmap);
      // use the codec to save Surface to stream
      if not TBitmapCodecManager.SaveToStream( 
                       Stream, 
                       Surf, 
                       '.png') then
        raise EBitmapSavingFailed.Create(
              'Error saving Bitmap to png');
    finally
      Surf.Free;
    end;
    // do something with the png stream image
    Stream.Position := 0;
    ImageViewer2.Bitmap.LoadFromStream(Stream);

    // comparison output as PNG from the stream
    Stream.Position := 0;
    Stream.SaveToFile(aFile+'.png');
  finally
    Stream.Free;
  end;
end;

Now, you can obviously save as a ‘PNG’ from the bitmap, but the above code shows how to avoid saving a file  to disk unless you really need to.

Happy coding!

2 thoughts on “Bitmap to PNG/JPEG/JPG in Delphi / C++Builder”

  1. Hi, i have an android application that saves photos in my database. The files stay with 350kb or more… before save in my database i want to convert to jpg with 50% compression… there is a way? i’m usint takephotofromcameraaction…

Leave a Reply

Your email address will not be published. Required fields are marked *