Author: Tomas Rutkauskas
Is there a simple way to write a TBitmap object to a file and read it back? I want
to store bitmaps and other data all in one file (much like word processors are
capable of doing).
Answer:
If you wish to store multiple things into a file, you'll need to implement some
sort of file structure so you can know what and where things are in the file. For
example, if you wished to store several bitmaps to a file, you could structure your
file like this:
file header
bitmap count
bitmap header
bitmap size
bitmap stream
bitmap trailer
...
file trailer
Where "file header" contains information such as the version of the file and a
unique file structure identifier, "bitmap count" is the number of bitmaps saved to
the file, "bitmap header" is a unique identifier which indicates the start of a
bitmap entry in the file, "bitmap size" is the size of the bitmap stream, "bitmap
stream" is the bitmap's stream (from SaveToStream), "bitmap trailer" is a trailer
identifier which indicates the end of the bitmap entry, and "file trailer" is a
unique identifier which indicates the end of the file, and optionally contains the
size of the file and a CRC of the file (for error detection). Of course, you'd
iterate the "bitmap header"..."bitmap trailer" structure once per bitmap saved to
the file.
You can use a TFileStream to read / write this structure. You'll need to write a
number of methods which read and interpret each section. You'll also want to create
a TBitmap instance each time you encounter a "bitmap header" structure. Here's a
quick example of how to implement the "bitmap header"..."bitmap trailer" section:
1 const
2 BITMAP_HEADER = 100;
3 BITMAP_TRAILER = 200;
4
5 procedure SaveBitmap(Bitmap: TBitmap; Stream: TStream);
6 var
7 Buffer: TMemoryStream;
8 Identifier: LongInt;
9 Size: LongInt;
10 begin
11 Buffer := TMemoryStream.Create;
12 try
13 Bitmap.SaveToStream(Buffer);
14 Identifier := BITMAP_HEADER;
15 Stream.write(Identifier, SizeOf(Identifier));
16 Size := Buffer.Size;
17 Stream.write(Size, SizeOf(Size));
18 Buffer.Position := 0;
19 Stream.CopyFrom(Buffer, Size);
20 Identifier := BITMAP_TRAILER;
21 Stream.write(Identifier, SizeOf(Identifier));
22 finally
23 Buffer.Free;
24 end;
25 end;
26
27 procedure ReadBitmap(Bitmap: TBitmap; Stream: TStream);
28 var
29 Buffer: TMemoryStream;
30 Identifier: LongInt;
31 Size: LongInt;
32 begin
33 Buffer := TMemoryStream.Create;
34 try
35 Stream.read(Identifier, SizeOf(Identifier));
36 if Identifier <> BITMAP_HEADER then
37 raise Exception.Create('Bitmap header expected');
38 Stream.read(Size, SizeOf(Size));
39 Buffer.CopyFrom(Stream, Size);
40 Bitmap.LoadFromStream(Buffer);
41 Stream.read(Identifier, SizeOf(Identifier));
42 if Identifier <> BITMAP_TRAILER then
43 raise Exception.Create('Bitmap trailer expected');
44 finally
45 Buffer.Free;
46 end;
47 end;
Of course, you'll need to write other methods to read the other file sections, and you'll need to call ReadBitmap the correct number of times (specified in "bitmap count") with a TBitmap instance.
|