source: trunk/dll/loadbmp.c@ 1844

Last change on this file since 1844 was 1673, checked in by Gregg Young, 13 years ago

Update to Doxygen comment style Ticket 55. Also some minor code cleanup.

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