source: trunk/dll/loadbmp.c@ 1158

Last change on this file since 1158 was 1158, checked in by John Small, 17 years ago

Ticket 187: Draft 1: Functions only

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