source: trunk/NewView/HelpBitmap.pas@ 18

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

+ newview source

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