How to save several TBitmaps into one file #100

Question
Does anybody know whether it is possible to write some small TBitmaps with different widths and heights into one file?

Saving the TBitmap to a stream, and appending other TBitmaps to that stream, then saving the stream to disk would be the method.

procedure SaveBitmapToStream(aBitmap: TBitmap; aStream: TStream);
var
  ms: TMemoryStream;
  size: Integer;
begin
  Assert(Assigned(aBitmap));
  Assert(Assigned(aStream));
  ms:= TMemoryStream.Create;
  try
    aBitmap.SaveToStream(ms);
    ms.position := 0;
    size := ms.Size;
    aStream.WriteBuffer(size, Sizeof(size));
    aStream.CopyFrom(ms, size);
  finally
    ms.free
  end;
end;

then

aStream.SaveToFile('FileName');

To read then first off do:

aStream.LoadFromFile('FileName');

then

procedure LoadBitmapFromStream(aBitmap: TBitmap; aStream: TStream);
var
  ms: TMemoryStream;
  size: Integer;
begin
  Assert(Assigned(aBitmap));
  Assert(Assigned(aStream));
  ms:= TMemoryStream.Create;
  try
    aStream.ReadBuffer(size, Sizeof(size));
    ms.CopyFrom(aStream, size);
    ms.position := 0;
    aBitmap.LoadfromStream(ms);
  finally
    ms.free
  end;
end;

Demo code

A ready made project containing this demo code is available. View the project.

This demo shows how to implement this tip. We will load two bitmaps into two image controls. Clicking a button will store those two bitmaps in a single file. A click on a second button will load the file, separate the bitmaps and display them in a second pair of image controls.

Start a new Delphi VCL application then proceed as follows:

  • Drop four image controls on the form. Load sample bitmaps into Image1 and Image2. Leave Image3 and Image4 empty.
  • Drop two TButtons onto the form and create an OnClick event handler for each button.
  • Name the form "Form1" and save the form unit as Unit1.pas.
  • Now code Unit1 as follows:
unit Unit1;

interface

uses
  SysUtils, Forms, Controls, StdCtrls, Graphics, Classes, ExtCtrls;

type
  TForm1 = class(TForm)
    Image1: TImage;
    Image2: TImage;
    Image3: TImage;
    Image4: TImage;
    Button1: TButton;
    Button2: TButton;
    procedure Button1Click(Sender: TObject);
    procedure Button2Click(Sender: TObject);
  end;

var
  Form1: TForm1;

implementation

{$R *.dfm}

const
  // test file name: change and/or provide a path if required
  cFileName = 'test';

procedure SaveBitmapToStream( aBitmap: TBitmap; aStream: TStream );
var
  ms: TMemoryStream;
  size: Integer;
begin
  Assert( Assigned(aBitmap));
  Assert( Assigned(aStream));
  ms:= TMemoryStream.Create;
  try
    aBitmap.SaveToStream(ms);
    ms.position := 0;
    size := ms.Size;
    aStream.WriteBuffer( size, Sizeof(size));
    aStream.CopyFrom(ms, size );
  finally
    ms.free
  end;
end;

procedure LoadBitmapFromStream(aBitmap: TBitmap; aStream: TStream );
var
  ms: TMemoryStream;
  size: Integer;
begin
  Assert( Assigned(aBitmap));
  Assert( Assigned(aStream));
  ms:= TMemoryStream.Create;
  try
    aStream.ReadBuffer( size, Sizeof(size));
    ms.CopyFrom(aStream, size );
    ms.position := 0;
    aBitmap.LoadfromStream(ms);
  finally
    ms.free
  end;
end;

{ TForm1 }

procedure TForm1.Button1Click(Sender: TObject);
var
  FS: TFileStream;
begin
  // Save Image1 and Image2 to single file
  FS := TFileStream.Create(cFileName, fmCreate);
  try
    SaveBitmapToStream(Image1.Picture.Bitmap, FS);
    SaveBitmapToStream(Image2.Picture.Bitmap, FS);
  finally
    FS.Free;
  end;
end;

procedure TForm1.Button2Click(Sender: TObject);
var
  FS: TFileStream;
begin
  // Load file, split up bitmaps and load into Image3 and Image4
  FS := TFileStream.Create(cFileName, fmOpenRead or fmShareDenyNone);
  try
    LoadBitmapFromStream(Image3.Picture.Bitmap, FS);
    LoadBitmapFromStream(Image4.Picture.Bitmap, FS);
  finally
    FS.Free;
  end;
end;

end.

Run the application and click Button1 to save the images to file. The file is named test and is stored in the demo executable's directory. If you don't have write access to the directory change the source to use a different directory. Click Button2 to read the file. The images should appear in the two empty image controls.

Demo by Peter Johnson

Original resource: The Delphi Pool
Author: Charles Hacker
Added: 2009/09/14
Last updated: 2010/03/16