source: branches/2.20_branch/NewView/HelpBitmap.pas@ 443

Last change on this file since 443 was 240, checked in by RBRi, 18 years ago

small format fix

  • Property svn:eol-style set to native
File size: 8.7 KB
Line 
1Unit HelpBitmap;
2
3// NewView - a new OS/2 Help Viewer
4// Copyright 2003 Aaron Lawrence (aaronl at consultant dot com)
5// This software is released under the Gnu Public License - see readme.txt
6
7Interface
8
9// Encapsulates a bitmap as stored in a IPF file.
10// Once created from file data they can be used as a normal bitmap.
11
12uses
13 BseDos,
14 OS2Def,
15 PMBitmap,
16 Classes,
17 Graphics,
18 SysUtils,
19 IPFFileFormatUnit;
20
21type
22 EHelpBitmapException = class( Exception )
23 end;
24
25 // Lead part of BITMAPARRAYFILEHEADER
26 INFBITMAPARRAYHEADER = record
27 usType: USHORT; // 'BA', 16706
28 cbSize: ULONG; // Size of the BITMAPARRAYFILEHEADER structure in bytes.
29 offNext: ULONG; // Offset of the next BITMAPARRAYFILEHEADER structure from the start of the file.
30 cxDisplay: USHORT; // Device width, in pels.
31 cyDisplay: USHORT; // Device height, in pels.
32 end;
33
34 INFBITMAPHEADER = record
35 // BITMAP FILE HEADER
36 usType: USHORT; // = 'bM'
37 cbSize: ULONG;
38 xHotspot: USHORT;
39 yHotspot: USHORT;
40 offBits: ULONG; // =size(hdr)+size(palette)
41 // BITMAP INFO HEADER
42 cbFIx: ULONG; // =size(info_hdr) (usually = 12?)
43 cx: USHORT; // x size
44 cy: USHORT; // y size
45 cPlanes: USHORT; // planes, =1
46 cBitCount: USHORT;
47 end;
48
49 THelpBitmap = class( TBitmap )
50 protected
51 _Header: INFBITMAPHEADER;
52 _PaletteColorCount: longint;
53 _pPalette: ^RGB;
54 _BitsSize: longint;
55 _FileHandle: HFile;
56
57 _UncompressedBlockSize: longint;
58
59 function GetPaletteSize: longint;
60 procedure ReadBitmapData( Blocks: TList;
61 TotalSize: longint );
62 public
63 constructor CreateFromHelpFile( FileHandle: HFile;
64 Offset: longint );
65 destructor Destroy; override;
66 end;
67
68var
69 LZWDecompressBlock: function( pInput: PBYTE;
70 pOutput: PBYTE;
71 bytesIn: ULONG;
72 Var bytesOut: ULONG;
73 Var FinalCode: byte ): BOOL;
74 APIENTRY;
75// 'newview' index 1;
76
77Implementation
78
79uses
80 ACLFileIOUtility,
81 ACLUtility,
82 ACLDialogs;
83
84const
85 BFT_bMAP =$4d62; // 'bM'
86 BFT_BITMAP_ARRAY = $4142; // 'BA'
87
88type
89 INFBITMAPDATAHEADER = record
90 ulTotalSize: ULONG;
91 usUncompressedBlockSize: USHORT; // bytes per block, after decompression
92 end;
93
94 TBitmapBlock = class
95 _Data: PBYTE;
96 _Size: USHORT;
97 _CompressionType: uint8;
98 destructor Destroy; override;
99 end;
100
101destructor TBitmapBlock.Destroy;
102begin
103 DeallocateMemory( _Data );
104 inherited Destroy;
105end;
106
107constructor THelpBitmap.CreateFromHelpFile( FileHandle: HFILE;
108 Offset: longint );
109var
110 WordsPerLine: longint;
111 LineSize: longint;
112 DataHeader: INFBITMAPDATAHEADER;
113 BytesRead: longint;
114
115 Block: TBitmapBlock;
116 Blocks: TList;
117 BlockIndex: longint;
118 ImageType: USHORT;
119 BitmapArrayHeader: INFBITMAPARRAYHEADER;
120begin
121 MySeek( FileHandle, Offset );
122 MyRead( FileHandle, Addr( ImageType ), sizeof( ImageType ) );
123
124 if ImageType = BFT_BITMAP_ARRAY then
125 begin
126 // skip array header and read first bitmap only
127 MySkip( FileHandle, Sizeof( BitmapArrayHeader ) - sizeof( ImageType ) );
128 end
129 else
130 begin
131 // skip back over imagetype bytes to read header.
132 MySkip( FileHandle, - sizeof( ImageType ) );
133 end;
134
135 // Read bitmap header
136 MyRead( FileHandle, Addr( _Header ), sizeof( _Header ) );
137
138 // Check it's got a valid type
139 if _Header.usType <> BFT_bMAP then
140 raise EHelpBitmapException.Create( 'Invalid bitmap header' );
141
142 _Header.usType := $4d42; // sibyl only accepts 'BM' not 'bM'
143
144 // We can only parse bitmaps with 1 colour plane
145 // (I can't be bothered and have never seen bitmaps
146 // with more than 1 color plane)
147 if _Header.cPlanes <> 1 then
148 exit;
149
150 _PaletteColorCount := 0;
151 if _Header.cBitCount < 24 then
152 _PaletteColorCount := 1 shl _Header.cBitCount;
153
154 // OS/2 always rounds bitmap rows up to a word:
155 WordsPerLine := ( _Header.cBitCount * _Header.cx + 31 ) div 32;
156 LineSize := WordsPerLine * 4;
157
158 // Total size of the bitmap pixel data
159 _BitsSize := LineSize * _Header.cy;
160
161 // Correct header offset - it is wrong in the header (why?)
162 _Header.OffBits := sizeof( _Header ) + GetPaletteSize;
163
164 // Load palette
165 _pPalette := AllocateMemory( GetPaletteSize );
166 MyRead( FileHandle, _pPalette, GetPaletteSize );
167
168 // Read data header
169 MyRead( FileHandle, Addr( DataHeader ), sizeof( DataHeader ) );
170 _UncompressedBlockSize := DataHeader.usUncompressedBlockSize;
171
172 // For counting total size, we have already read some bytes:
173 // the uncompressedblocksize field
174 BytesRead := sizeof( DataHeader.usUncompressedBlockSize );
175 Blocks := TList.Create;
176
177 while BytesRead < DataHeader.ulTotalSize do
178 begin
179 Block := TBitmapBlock.Create;
180
181 // Read the block size
182 MyRead( FileHandle, Addr( Block._Size ), sizeof( Block._Size ) );
183 inc( BytesRead, sizeof( Block._Size ) );
184
185 // Read the compression type
186 MyRead( FileHandle, Addr( Block._CompressionType ), sizeof( Block._CompressionType ) );
187 inc( BytesRead, sizeof( Block._CompressionType ) );
188
189 // since size in the file includes this compression type field, subtract it
190 dec( Block._Size, sizeof( Block._CompressionType ) );
191
192 // Now read the block
193 Block._Data := AllocateMemory( Block._Size );
194 MyRead( FileHandle, Block._Data, Block._Size );
195
196 inc( BytesRead, Block._Size );
197
198 Blocks.Add( Block );
199
200 end;
201 ReadBitmapData( Blocks, sizeof( _Header ) + GetPaletteSize + _BitsSize );
202
203 for BlockIndex := 0 to Blocks.Count - 1 do
204 begin
205 Block := Blocks[ BlockIndex ];
206 Block.Destroy;
207 end;
208
209 Blocks.Destroy;
210end;
211
212function THelpBitmap.GetPaletteSize: longint;
213begin
214 Result := sizeof( RGB ) * _PaletteColorCount;
215end;
216
217destructor THelpBitmap.Destroy;
218begin
219 DeallocateMemory( _pPalette );
220 inherited Destroy;
221end;
222
223procedure THelpBitmap.ReadBitmapData( Blocks: TList;
224 TotalSize: longint );
225var
226 BytesWritten: longint;
227 BytesWrittenFromBlock: longword;
228 BytesRemainingInBlock: longword;
229 BytesRemainingInBitmap: longword;
230 FillerBytesRequired: longint;
231 lastOutByte: byte;
232 BitmapOutputPointer: PByte;
233 Block: TBitmapBlock;
234 BlockIndex: longint;
235 BitmapData: PBYTE;
236begin
237 // Allocate memory to store the bitmap
238 GetMem( BitmapData, TotalSize );
239
240 // Copy header to bitmap
241 MemCopy( Addr( _Header ),
242 BitmapData,
243 sizeof( _Header ) );
244
245 // Copy palette into bitmap
246 MemCopy( _pPalette,
247 BitmapData + sizeof( _Header ),
248 GetPaletteSize );
249
250 BytesWritten := 0;
251
252 // Point to start writing to bitmap bits.
253 BitmapOutputPointer := BitmapData + sizeof( _Header ) + GetPaletteSize;
254
255 for BlockIndex := 0 to Blocks.Count - 1 do
256 begin
257 Block := Blocks[ BlockIndex ];
258
259 case Block._CompressionType of
260 0,1: // uncompressed (I'm not sure about 1)
261 begin
262 MemCopy( Block._Data,
263 BitmapOutputPointer,
264 Block._Size );
265 BytesWrittenFromBlock := Block._Size;
266 inc( BytesWritten, BytesWrittenFromBlock );
267 end;
268
269 2: // LZW compression
270 begin
271 // decompress block
272 if not Assigned( LZWDecompressBlock )then
273 raise EHelpBitmapException.Create( 'Cannot decode bitmap - DLL not found' );
274
275 LZWDecompressBlock( Block._Data,
276 BitmapOutputPointer,
277 Block._Size,
278 BytesWrittenFromBlock,
279 lastOutByte );
280
281 inc( BytesWritten, BytesWrittenFromBlock );
282
283 // If the uncompressed data stopped short then
284 // copy the final code (byte) into remaining bytes
285 if ( BytesWrittenFromBlock < _UncompressedBlockSize )
286 and ( BytesWritten < _BitsSize ) then
287 begin
288 BytesRemainingInBlock := _UncompressedBlockSize - BytesWrittenFromBlock;
289 BytesRemainingInBitmap := _BitsSize - BytesWritten;
290
291 FillerBytesRequired := Min( BytesRemainingInBlock,
292 BytesRemainingInBitmap );
293
294 FillMem( BitmapOutputPointer + BytesWrittenFromBlock,
295 FillerBytesRequired,
296 LastOutByte );
297 inc( BytesWritten, FillerBytesRequired );
298 inc( BytesWrittenFromBlock, FillerBytesRequired );
299 end;
300 end;
301 else
302 raise EHelpBitmapException.Create( 'Unrecognised bitmap block type' );
303 end; // case
304
305 assert( BytesWrittenFromBlock <= _UncompressedBlockSize );
306 assert( BytesWritten <= _BitsSize );
307
308 if ( BitmapOutputPointer + BytesWrittenFromBlock
309 > BitmapData + TotalSize ) then
310 assert( false );
311
312 inc( BitmapOutputPointer, BytesWrittenFromBlock );
313 end;
314
315 LoadFromMem( BitmapData^, TotalSize );
316 FreeMem( BitmapData, TotalSize );
317end;
318
319Initialization
320End.
Note: See TracBrowser for help on using the repository browser.