source: trunk/dll/loadbmp.c@ 549

Last change on this file since 549 was 549, checked in by root, 19 years ago

Support additional file systems types (Gregg)
Reorganize menus (Gregg)
Enhance unzip option controls (Gregg)
Remember search options in Seek and Scan (Gregg)
Allow drive flag editing for not ready drives (Gregg)
Correct bitmap loading defects (Steven)
Update documentation (Gregg)
Add newer, better bitmaps (David)
Update Readme to discuss move to Netlabs (Steve)

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 10.3 KB
Line 
1
2/***********************************************************************
3
4 $Id: loadbmp.c 549 2007-02-04 03:14:36Z root $
5
6 Load bitmaps
7
8 Copyright (c) 1993-98 M. Kimes
9 Copyright (c) 2006, 2007 Steven H.Levine
10
11 22 Jul 06 SHL Check more run time errors
12 16 Jan 07 SHL Check more run time errors
13 16 Jan 07 SHL Sync variable names for sanity
14 16 Jan 07 SHL Open bitmap file binary - no wonder the code does not work
15 16 Jan 07 SHL Beautify with indent -i2
16
17***********************************************************************/
18
19#define INCL_DOS
20#define INCL_WIN
21#define INCL_GPI
22#include <os2.h>
23
24#include <stdlib.h>
25#include <stdio.h>
26#include <string.h>
27#include <share.h>
28
29#include "fm3dll.h"
30
31static PSZ pszSrcFile = __FILE__;
32
33#pragma alloc_text(LOADBITMAP,LoadBitmapFromFile,LoadBitmapFromFileNum)
34
35HBITMAP LoadBitmapFromFileNum(USHORT id)
36{
37 char s[CCHMAXPATH];
38
39 save_dir2(s);
40 sprintf(s + strlen(s), "\\%u.BMP", id);
41 return LoadBitmapFromFile(s);
42}
43
44HBITMAP LoadBitmapFromFile(CHAR * pszFileName)
45{
46 HBITMAP hBmp = (HBITMAP) 0;
47 FILE *pf;
48 ULONG rc;
49 USHORT usType;
50 PBITMAPARRAYFILEHEADER2 pbmafh2 = NULL; // Must init for xfree
51 PBITMAPFILEHEADER2 pbmfh2; // No color table
52 PBITMAPINFOHEADER2 pbmih2; // No color table
53 PBITMAPINFO2 pbmi2; // Includes color table
54 BOOL is2x; // Format 1.x or 2.x
55 ULONG ulColors;
56 ULONG ulRGBOffset;
57 PBYTE pData = NULL; // Must init for xfree
58 ULONG ulDataSize;
59 SIZEL sizel;
60 HPS hPS = WinGetPS(HWND_DESKTOP);
61
62 if (!hPS) {
63 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
64 "WinGetPS");
65 goto ExitLoadBMP;
66 }
67
68 pf = _fsopen(pszFileName, "rb", SH_DENYWR);
69 if (!pf) {
70 // OK for file to not exist - enable following for debug as needed
71 // Runtime_Error(pszSrcFile, __LINE__, "_fsopen %s", pszFileName);
72 goto ExitLoadBMP;
73 }
74
75 // Read image type
76 // fixme to just read type2 header - this is silly and wastes time
77 rc = fread(&usType, 1, sizeof(usType), pf);
78 if (rc != sizeof(usType)) {
79 Runtime_Error(pszSrcFile, __LINE__, "fread");
80 goto ExitLoadBMP;
81 }
82
83 /* Read bitmap info header
84 Allocate enough to hold a complete 2.x bitmap array file header
85 fixme to support > 256 colors?
86 */
87 pbmafh2 =
88 xmalloc(sizeof(*pbmafh2) + 256 * sizeof(RGB2), pszSrcFile, __LINE__);
89 if (!pbmafh2)
90 goto ExitLoadBMP;
91 /* Assign pointers to the file header and bitmap info header etc.
92 Both the 1.x and 2.x structures are assigned to simplify code
93 fixme to clean this up - aliased pointers are evil
94 */
95 pbmfh2 = &pbmafh2->bfh2;
96 pbmih2 = &pbmfh2->bmp2;
97 pbmi2 = (PBITMAPINFO2)pbmih2;
98
99 switch (usType) {
100 case BFT_BMAP:
101 case BFT_ICON:
102 case BFT_POINTER:
103 case BFT_COLORICON:
104 case BFT_COLORPOINTER:
105 {
106 /* Assume image is a 2.0 image and read as a 2.x header
107 OK for 1.x file - read will not fail unless file is corrupted
108 */
109 rc = fseek(pf, 0, SEEK_SET);
110 if (rc) {
111 Runtime_Error(pszSrcFile, __LINE__, "fseek 0");
112 goto ExitLoadBMP;
113 }
114
115 rc = fread(pbmfh2, 1, sizeof(*pbmfh2), pf);
116 if (rc != sizeof(*pbmfh2)) {
117 Runtime_Error(pszSrcFile, __LINE__, "fread");
118 goto ExitLoadBMP;
119 }
120
121 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER); // 1.x or 2.x bitmap
122 /* We will read the color table later
123 Color table follows header but
124 location depends on the type of the bitmap (old vs new)
125 1.x header is fixed size
126 2.x header is variable sized, so offset must be calculated
127 cbFix contains actual size of BITMAPINFOHEADER2 in file
128 */
129 ulRGBOffset = is2x ? sizeof(*pbmfh2) - sizeof(*pbmih2) + pbmih2->cbFix :
130 sizeof(BITMAPFILEHEADER);
131 }
132 break;
133
134 case BFT_BITMAPARRAY:
135 {
136 /* Now we are dealing with a bitmap array which is a collection of bitmaps
137 Each bitmap has its own file header
138 */
139
140 ULONG ulCurOffset;
141 ULONG clScreenWidth;
142 ULONG clScreenHeight;
143 ULONG ulDeviceColors;
144 ULONG ulSizeDiff;
145 ULONG ulOffsetPicked = 0;
146 ULONG ulColorsPicked;
147 ULONG ulSizeDiffPicked;
148 HDC hdc;
149
150 /* Scan the array and chose the bitmap best suited
151 for the current display size and color capacities
152 */
153 hdc = GpiQueryDevice(hPS);
154 if (!hdc) {
155 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
156 "GpiQueryDevice");
157 goto ExitLoadBMP;
158 }
159 DevQueryCaps(hdc, CAPS_COLORS, 1, (PLONG)&ulDeviceColors);
160 DevQueryCaps(hdc, CAPS_WIDTH, 1, (PLONG)&clScreenWidth);
161 DevQueryCaps(hdc, CAPS_HEIGHT, 1, (PLONG)&clScreenHeight);
162 pbmafh2->offNext = 0;
163 do {
164 ulCurOffset = pbmafh2->offNext;
165 rc = fseek(pf, pbmafh2->offNext, SEEK_SET);
166 if (rc) {
167 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmafh2->offNext);
168 goto ExitLoadBMP;
169 }
170 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
171 if (rc != sizeof(*pbmafh2)) {
172 Runtime_Error(pszSrcFile, __LINE__, "fread");
173 goto ExitLoadBMP;
174 }
175 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
176 if (is2x) {
177 ulColors = 1 << (pbmafh2->bfh2.bmp2.cBitCount *
178 pbmafh2->bfh2.bmp2.cPlanes);
179 }
180 else {
181 ulColors = 1 << (((PBITMAPARRAYFILEHEADER)pbmafh2)->bfh.bmp.cBitCount *
182 ((PBITMAPARRAYFILEHEADER)pbmafh2)->bfh.bmp.cPlanes);
183 }
184 if (pbmafh2->cxDisplay == 0 && pbmafh2->cyDisplay == 0) {
185 // This is a device independant bitmap - process it as a VGA
186 pbmafh2->cxDisplay = 640;
187 pbmafh2->cyDisplay = 480;
188 }
189 ulSizeDiff = abs(pbmafh2->cxDisplay - clScreenWidth) +
190 abs(pbmafh2->cyDisplay - clScreenHeight);
191 if (ulDeviceColors == ulColors && ulSizeDiff == 0) {
192 // We found the perfect match
193 ulOffsetPicked = ulCurOffset;
194 break; // Stop scan
195 }
196 if (ulOffsetPicked == 0 || // First time thru
197 ulSizeDiff < ulSizeDiffPicked || // Better fit than any previous
198 (ulColors > ulColorsPicked && ulColors < ulDeviceColors) || // More colors than prev & less than device
199 (ulColors < ulColorsPicked && ulColors > ulDeviceColors))
200 {
201 ulOffsetPicked = ulCurOffset; // Make this our current pick
202 ulColorsPicked = ulColors;
203 ulSizeDiffPicked = ulSizeDiff;
204 }
205 } while (pbmafh2->offNext != 0);
206
207 // Retrieve the selected bitmap
208 rc = fseek(pf, ulOffsetPicked, SEEK_SET);
209 if (rc) {
210 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulOffsetPicked);
211 goto ExitLoadBMP;
212 }
213 rc = fread(pbmafh2, 1, sizeof(*pbmafh2), pf);
214 if (rc != sizeof(*pbmafh2)) {
215 Runtime_Error(pszSrcFile, __LINE__, "fread");
216 goto ExitLoadBMP;
217 }
218
219 is2x = pbmih2->cbFix > sizeof(BITMAPINFOHEADER);
220 /* As before, we calculate offset in file stream to color table
221 This code must match single bitmap logic
222 */
223 ulRGBOffset = ulOffsetPicked;
224 ulRGBOffset += is2x ? sizeof(*pbmafh2) - sizeof(*pbmih2) + pbmih2->cbFix :
225 sizeof(BITMAPARRAYFILEHEADER);
226 }
227 break;
228
229 default:
230 Runtime_Error(pszSrcFile, __LINE__, "Bad type %u", usType);
231 goto ExitLoadBMP;
232 } // endswitch
233
234 // Position to color table
235 rc = fseek(pf, ulRGBOffset, SEEK_SET);
236 if (rc) {
237 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", ulRGBOffset);
238 goto ExitLoadBMP;
239 }
240
241 // Read color table
242 if (is2x) {
243 /* For a 2.0 bitmap, read the color table as is
244 The bitmap info structure is header + color table
245 If we have 24 bits per pel, there is usually no color table, unless
246 pbmih2->cclrUsed or pbmih2->cclrImportant are non zero
247 fixme to test this
248 */
249 if (pbmih2->cBitCount < 24) {
250 ULONG ulRGBBytes;
251 ulColors = 1L << pbmih2->cBitCount;
252
253 if (ulColors > 256) {
254 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu", ulColors);
255 goto ExitLoadBMP;
256 }
257 ulRGBBytes = ulColors * sizeof(RGB2);
258 rc = fread(&pbmi2->argbColor[0], 1, ulRGBBytes, pf);
259 if (rc != ulRGBBytes) {
260 Runtime_Error(pszSrcFile, __LINE__, "fread");
261 goto ExitLoadBMP;
262 }
263 } // endif
264 // Get pointer to bitmap info (header and color table)
265 pbmi2 = (PBITMAPINFO2)pbmih2;
266 }
267 else {
268 /* This is a 1.x format bitmap
269 Since the current standard format is the 2.0
270 convert the header and color table to 2.x format
271 */
272 ULONG ul;
273 RGB rgb;
274 PBITMAPINFOHEADER pbmih = &((PBITMAPARRAYFILEHEADER)pbmafh2)->bfh.bmp;
275
276 if (pbmih->cBitCount < 24) {
277 ulColors = 1 << pbmih->cBitCount;
278 if (ulColors > 256) {
279 Runtime_Error(pszSrcFile, __LINE__, "RGB exceeds 256 colors: %lu", ulColors);
280 goto ExitLoadBMP;
281 }
282 // Read in 1.x color table and reformat for 2.x
283 for (ul = 0; ul < ulColors; ul++) {
284 fread(&rgb, 1, sizeof(rgb), pf);
285 pbmi2->argbColor[ul].bRed = rgb.bRed;
286 pbmi2->argbColor[ul].bGreen = rgb.bGreen;
287 pbmi2->argbColor[ul].bBlue = rgb.bBlue;
288 pbmi2->argbColor[ul].fcOptions = 0; // initialize 2.x extra byte to 0
289 } // for
290 }
291
292 // Convert the old style to the new header format
293 pbmi2->cbFix = sizeof(BITMAPINFOHEADER2);
294 pbmi2->cBitCount = pbmih->cBitCount;
295 pbmi2->cPlanes = pbmih->cPlanes;
296 pbmi2->cy = pbmih->cy;
297 pbmi2->cx = pbmih->cx;
298 // set rest to zero
299 memset((PCHAR)pbmi2 + 16, 0, sizeof(BITMAPINFOHEADER2) - 16);
300 } // if 1.x
301
302 /* The 2.0 bitmap info structure set up
303 Position to start of the bitmap data
304 */
305 rc = fseek(pf, pbmfh2->offBits, SEEK_SET);
306 if (rc) {
307 Runtime_Error(pszSrcFile, __LINE__, "fseek %ld", pbmfh2->offBits);
308 goto ExitLoadBMP;
309 }
310
311 /* Read the bitmap data
312 The read size is derived using the magic formula
313 Each bitmap scan line is aligned on a doubleword boundary
314 The size of the scan line is the number of pels times the bpp
315 After aligning it, we divide by 4 to get the number of bytes, and
316 multiply by the number of scan lines and the number of pel planes
317 */
318 if (pbmi2->ulCompression)
319 ulDataSize = pbmi2->cbImage;
320 else
321 ulDataSize = (((pbmi2->cBitCount * pbmi2->cx) + 31) / 32) * 4 *
322 pbmi2->cy * pbmi2->cPlanes;
323 pData = xmalloc(ulDataSize, pszSrcFile, __LINE__);
324 if (!pData)
325 goto ExitLoadBMP;
326 rc = fread(pData, 1, ulDataSize, pf);
327 if (rc != ulDataSize) {
328 Runtime_Error(pszSrcFile, __LINE__, "fread");
329 goto ExitLoadBMP;
330 }
331
332 // Create the GPI bitmap image
333 sizel.cx = pbmi2->cx;
334 sizel.cy = pbmi2->cy;
335
336 hBmp = GpiCreateBitmap(hPS, (PBITMAPINFOHEADER2) pbmi2, CBM_INIT,
337 pData, pbmi2);
338 if (!hBmp)
339 Win_Error(HWND_DESKTOP, HWND_DESKTOP, pszSrcFile, __LINE__,
340 "GpiCreateBitmap");
341
342ExitLoadBMP:
343
344 xfree(pData);
345 xfree(pbmafh2);
346 if (pf)
347 fclose(pf);
348 if (hPS)
349 WinReleasePS(hPS);
350 return hBmp;
351}
Note: See TracBrowser for help on using the repository browser.