source: trunk/src/kernel32/cvtbitmap.cpp@ 22018

Last change on this file since 22018 was 2802, checked in by sandervl, 26 years ago

Added new logging feature

File size: 23.8 KB
Line 
1/* $Id: cvtbitmap.cpp,v 1.3 2000-02-16 14:25:36 sandervl Exp $ */
2
3/*
4 * PE2LX bitmap conversion code
5 *
6 * Copyright 1998 Sander van Leeuwen (sandervl@xs4all.nl)
7 * Copyright 1998 Knut St. Osmundsen
8 *
9 *
10 * Project Odin Software License can be found in LICENSE.TXT
11 *
12 */
13#define INCL_GPIBITMAPS
14#define INCL_BITMAPFILEFORMAT
15#define INCL_DOSFILEMGR /* File Manager values */
16#define INCL_DOSERRORS /* DOS Error values */
17#define INCL_DOSPROCESS /* DOS Process values */
18#define INCL_DOSMISC /* DOS Miscellanous values */
19#define INCL_WIN
20#include <os2wrap.h>
21#include <stdio.h>
22#include <string.h>
23#include <stdlib.h>
24#include <string.h>
25#include <assert.h>
26#include <win32type.h>
27#include <winicon.h>
28#include <misc.h>
29#include "cvtresource.h"
30
31#define DBG_LOCALLOG DBG_cvtbitmap
32#include "dbglocal.h"
33
34#define __StackToFlat(a) a
35#define ltassert(a)
36#define MAXPTR
37#define MINPTR
38
39/**********/
40/* Macros */
41/**********/
42#define Need1BitTo4BitConvertWIN(pBHdr) \
43 ( \
44 pBHdr->biBitCount == 1 \
45 && !( \
46 (((PULONG)pBHdr)[10] == 0x00000000 && (pBHdr->biClrUsed == 1 || ((PULONG)pBHdr)[11] == 0x00ffffff)) /*black and white*/ \
47 || (((PULONG)pBHdr)[10] == 0x00ffffff && (pBHdr->biClrUsed == 1 || ((PULONG)pBHdr)[11] == 0x00000000)) /*white and black*/ \
48 ) \
49 )
50
51#define Need1BitTo4BitConvertOS2(pBIH) \
52 ( \
53 pBIH->cBitCount == 1 \
54 && !( \
55 (((PULONG)pBIH)[3] == 0x0ff00000 && ((PUSHORT)pBIH)[8] == 0xffff) /*black and white*/ \
56 || (((PULONG)pBIH)[3] == 0x00ffffff && ((PUSHORT)pBIH)[8] == 0x0000) /*white and black*/ \
57 ) \
58 )
59
60static ULONG Convert1BitTo4Bit(void *pNewData, PBYTE pbOldData, LONG cx, LONG cy);
61static ULONG QueryPaletteSize(WINBITMAPINFOHEADER *pBHdr);
62static ULONG QueryPaletteSize(BITMAPINFOHEADER *pBHdr);
63static ULONG QueryPaletteSize(BITMAPINFOHEADER2 *pBHdr);
64static ULONG CalcBitmapSize(ULONG cBits, LONG cx, LONG cy);
65
66//******************************************************************************
67//******************************************************************************
68void *ConvertBitmap(WINBITMAPINFOHEADER *pBHdr, ULONG ulSize, PULONG pulSize)
69{
70 ltassert((ULONG)pBHdr > MINPTR && (ULONG)pBHdr+ulSize < MAXPTR);
71
72 switch (pBHdr->biSize)
73 {
74 /**************************************/
75 /* Windows v3.0 bitmap */
76 /**************************************/
77 case sizeof(WINBITMAPINFOHEADER):
78 {//convert to OS/2 v2.0 bitmap
79 PBITMAPFILEHEADER2 pBFH;
80 ULONG cbPalette;
81 ULONG cbImage;
82 BOOL fConvert1Bit = FALSE;
83
84 dprintf(("Windows v3.0 bitmap"));
85 dprintf((" Size: %d", pBHdr->biSizeImage));
86 dprintf((" Width: %d", pBHdr->biWidth));
87 dprintf((" Height: %d", pBHdr->biHeight));
88 dprintf((" Bitcount: %d", pBHdr->biBitCount));
89 dprintf((" Compress: %d", pBHdr->biCompression));
90
91 fConvert1Bit = Need1BitTo4BitConvertWIN(pBHdr);
92
93 cbPalette = QueryPaletteSize(pBHdr);
94 ltassert(cbPalette != -1);
95 dprintf((" PaletteSize: %d", cbPalette));
96
97 /* calc bitmap size and allocate */
98#ifdef BITFIELDS
99 if (pBHdr->biCompression == BI_RGB || pBHdr->biCompression == BI_BITFIELDS)
100#else
101 if (pBHdr->biCompression == BI_RGB)
102#endif
103 {
104 /* recalc for non-compressed images */
105 if (fConvert1Bit)
106 cbImage = CalcBitmapSize(4, pBHdr->biWidth, pBHdr->biHeight);
107 else cbImage = CalcBitmapSize(pBHdr->biBitCount, pBHdr->biWidth, pBHdr->biHeight);
108 }
109 else
110 {
111 ltassert(!fConvert1Bit);
112 cbImage = pBHdr->biSizeImage;
113 if (cbImage == 0)
114 cbImage = ulSize - sizeof(WINBITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER2);
115 }
116 ltassert(cbImage != 0);
117
118 //bounds checking
119 if (!fConvert1Bit)
120 { /* brackets must not be removed! */
121 ltassert(cbImage <= ulSize - sizeof(WINBITMAPINFOHEADER) - cbPalette);
122 }
123 else ltassert(CalcBitmapSize(pBHdr->biBitCount, pBHdr->biWidth, pBHdr->biHeight) <= ulSize - sizeof(WINBITMAPINFOHEADER) - cbPalette);
124
125 *pulSize = sizeof(BITMAPFILEHEADER2) + cbPalette + cbImage;
126
127 dprintf((" Debug: Size(recalced): %d", cbImage));
128 dprintf((" Debug: Size in : %d", ulSize));
129 dprintf((" Debug: Size out : %D", *pulSize));
130
131 pBFH = (PBITMAPFILEHEADER2)malloc(*pulSize + 0x10);//allocate more than we need!
132 ltassert(pBFH);
133
134 /* file header */
135 pBFH->usType = BFT_BMAP;
136 pBFH->cbSize = sizeof(BITMAPFILEHEADER2);
137 pBFH->xHotspot = 0;
138 pBFH->yHotspot = 0;
139 pBFH->offBits = sizeof(BITMAPFILEHEADER2) + cbPalette;
140
141 /* info header*/
142 memset((void*)&pBFH->bmp2, 0, sizeof(BITMAPINFOHEADER2));
143 memcpy((void*)&pBFH->bmp2, (void*)pBHdr, sizeof(WINBITMAPINFOHEADER));
144 pBFH->bmp2.cbFix = sizeof(BITMAPINFOHEADER2);
145
146 /* bitfields */
147 if (pBFH->bmp2.ulCompression == BI_BITFIELDS)
148 {//TODO: Identical except for BI_BITFIELDS (3L) type! - cast a warning note
149 /* KSO: I need files to test it on */
150#ifndef BITFIELDS
151 dprintf(("Warning: ulCompression = BI_BITFIELDS"));
152 pBFH->bmp2.ulCompression = BCA_UNCOMP; //since BI_BITFIELDS == BCA_RLE24
153#else
154#error("Sorry, BITFIELDS are not implmented yet.")
155 /* generate new palette */
156 /* convert bitmap data */
157 /* update fileheader */
158#endif //#ifdef BITFIELDS
159 }
160
161 /* palette */
162 if (cbPalette > 0)
163 memcpy((void*)((ULONG)pBFH + sizeof(BITMAPFILEHEADER2)), (void*)((ULONG)pBHdr + sizeof(WINBITMAPINFOHEADER)), cbPalette);
164
165 /* bitmap data */
166 if (fConvert1Bit)
167 {
168 /* convert */
169 Convert1BitTo4Bit(
170 (PVOID)((ULONG)pBFH + sizeof(BITMAPFILEHEADER2) + cbPalette),
171 (PBYTE)((ULONG)pBHdr + sizeof(WINBITMAPINFOHEADER)+ cbPalette),
172 pBFH->bmp2.cx,
173 pBFH->bmp2.cy
174 );
175
176 /* update some infoheader fields */
177 pBFH->bmp2.cBitCount = 4;
178 if (pBFH->bmp2.cclrUsed == 0)
179 pBFH->bmp2.cclrUsed = 2;
180 if (pBFH->bmp2.cbImage != 0)
181 pBFH->bmp2.cbImage = cbImage;
182 }
183 else memcpy((void*)((ULONG)pBFH + sizeof(BITMAPFILEHEADER2) + cbPalette), (void*)((ULONG)pBHdr + sizeof(WINBITMAPINFOHEADER) + cbPalette), cbImage);
184
185 return pBFH;
186 }
187
188 /**************************************/
189 /* Windows v4.0 bitmap */
190 /**************************************/
191 case sizeof(BITMAPV4HEADER):
192 {//convert to OS/2 v2.0 bitmap - some other day when I find the specs.
193 dprintf(("Windows v4.0 bitmap"));
194 dprintf((" Not supported yet!"));
195 ltassert(FALSE && "Windows v4.0 bitmap");
196 break;
197 }
198
199 /**************************************/
200 /* OS/2 v1.x bitmap */
201 /**************************************/
202 case sizeof(BITMAPINFOHEADER):
203 {//no conversion needed - only build fileheader
204 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER)pBHdr;
205 PBITMAPFILEHEADER pBFH ;
206 BOOL fConvert1Bit;
207 ULONG cbPalette;
208
209 cbPalette = QueryPaletteSize(pBIH);
210 ltassert(cbPalette != -1);
211 *pulSize = ulSize + sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER);
212
213 fConvert1Bit = Need1BitTo4BitConvertOS2(pBIH);
214 if (fConvert1Bit)
215 *pulSize += (ulSize - cbPalette - sizeof(BITMAPINFOHEADER))*3 + 14 * sizeof(RGB);
216
217 pBFH = (PBITMAPFILEHEADER)malloc(*pulSize);
218 ltassert(pBFH != NULL);
219
220 if (fConvert1Bit)
221 {
222 /* copy infoheader */
223 memcpy(&pBFH->bmp, pBIH, sizeof(pBFH->bmp));
224 memset((void*)((ULONG)pBFH + sizeof(*pBFH)), 0, 16*sizeof(RGB));
225 memcpy((void*)((ULONG)pBFH + sizeof(*pBFH)), (void*)((ULONG)pBIH + sizeof(*pBIH)), 2*sizeof(RGB));
226 *pulSize = Convert1BitTo4Bit(
227 (PVOID)((ULONG)pBFH + sizeof(BITMAPFILEHEADER) + 16 * sizeof(RGB)),
228 (PBYTE)((ULONG)pBHdr + sizeof(BITMAPINFOHEADER) + cbPalette),
229 pBFH->bmp.cx,
230 pBFH->bmp.cy
231 );
232
233 /* update infoheader */
234 pBFH->bmp.cBitCount = 4;
235 cbPalette = 16 * sizeof(RGB); //used in fileheader
236 }
237 else
238 {
239 /* copy entire bitmap from infoheader */
240 memcpy(&pBFH->bmp, pBIH, ulSize);
241 *pulSize = CalcBitmapSize(pBIH->cBitCount, pBIH->cx, pBIH->cy);
242 ltassert(*pulSize != 0);
243 }
244 *pulSize += sizeof(BITMAPFILEHEADER) + cbPalette;
245
246 /* fileheader */
247 pBFH->usType = BFT_BMAP;
248 pBFH->cbSize = sizeof(BITMAPFILEHEADER);
249 pBFH->xHotspot = 0;
250 pBFH->yHotspot = 0;
251 pBFH->offBits = sizeof(BITMAPFILEHEADER) + cbPalette;
252
253 /* log info */
254 dprintf(("OS/2 v1.x bitmap"));
255 dprintf((" Width: %d", pBFH->bmp.cx));
256 dprintf((" Height: %d", pBFH->bmp.cy));
257 dprintf((" Bitcount: %d", pBFH->bmp.cBitCount));
258 dprintf((" PaletteSize: %d", cbPalette));
259 dprintf(("debug 1"));
260
261 return (void*)pBFH;
262 }
263
264 /**************************************/
265 /* OS/2 v2.0 bitmap - highly unlikely!*/
266 /**************************************/
267 case sizeof(BITMAPINFOHEADER2):
268 {//no conversion needed - only build fileheader
269 PBITMAPFILEHEADER2 pBFH;
270
271 pBFH = (PBITMAPFILEHEADER2)malloc(ulSize + sizeof(BITMAPFILEHEADER2) - sizeof(BITMAPINFOHEADER2));
272 ltassert(pBFH != NULL);
273
274 memcpy(&pBFH->bmp2, pBHdr, ulSize);
275
276 pBFH->usType = BFT_BMAP;
277 pBFH->cbSize = sizeof(BITMAPFILEHEADER2);
278 pBFH->xHotspot = 0;
279 pBFH->yHotspot = 0;
280 pBFH->offBits = sizeof(BITMAPFILEHEADER2);
281
282 dprintf(("OS/2 v2.0 bitmap"));
283 dprintf((" Width: %d", pBFH->bmp2.cx));
284 dprintf((" Height: %d", pBFH->bmp2.cy));
285 dprintf((" Bitcount: %d", pBFH->bmp2.cBitCount));
286
287 if (pBFH->bmp2.cBitCount < 24)
288 pBFH->offBits += ( 1, pBFH->bmp2.cBitCount ) * sizeof(RGB2);
289 else pBFH->offBits += pBFH->bmp2.cclrUsed;
290
291 return pBFH;
292 }
293
294
295 /**************************************/
296 /* Unknown */
297 /**************************************/
298 default: //fail
299 dprintf(("ConvertBitmap - default - fail!"));
300 return NULL;
301 }
302
303 return NULL;
304}
305//******************************************************************************
306//******************************************************************************
307/* Converting 1 bit bitmaps to 4 bit bitmaps
308 */
309//******************************************************************************
310//******************************************************************************
311static ULONG Convert1BitTo4Bit(void *pNewData, PBYTE pbOldData, LONG cx, LONG cy)
312{
313 PBYTE pbNewData = (PBYTE)pNewData;
314
315 dprintf((" 1->4 convert"));
316
317 //negative height
318 cy = cy < 0 ? -cy : cy;
319
320 *pbNewData = 0;
321 for (int y = 0; y < cy; y++)
322 {//outer loop: lines
323 int x;
324
325 for (x = 0; x < cx; x++)
326 {//inner loop: scanline
327 int iBit = 7-(x%8);
328 *pbNewData |= (((0x1, iBit) & *pbOldData) >> iBit), (iBit%2)*4;
329
330 if (x % 2)
331 {
332 pbNewData++;
333 *pbNewData = 0;
334 }
335
336 if ((x+1) % 8 == 0)
337 pbOldData++;
338 }
339
340 //next byte
341 if (x % 2)
342 {
343 pbNewData++;
344 *pbNewData = 0;
345 }
346 if ((x+1) % 8 == 0)
347 pbOldData++;
348
349 //aligning
350 for (int a = ((x+1)/2)%4; a < 4 && a != 0; a++)
351 {
352 pbNewData++;
353 *pbNewData = 0;
354 }
355 for (int b = ((x+7)/8)%4; b < 4 && b != 0; b++)
356 pbOldData++;
357 }
358
359 return (int)pbNewData - (int)pNewData;
360}
361//******************************************************************************
362//******************************************************************************
363static ULONG QueryPaletteSize(WINBITMAPINFOHEADER *pBHdr)
364{
365 ULONG cbPalette;
366
367 switch (pBHdr->biBitCount)
368 {
369 case 1:
370 case 4:
371 case 8:
372 /* Windows Bitmaps seems to have a full palette even when it don't use all of it - OS/2 does not...
373 Good for us, the fileheader holds the offset to the bitmap data - which means that this not should be a problem, luckily. */
374 //cbPalette = ((pBHdr->biClrUsed != 0) ? pBHdr->biClrUsed : 1, pBHdr->biBitCount) * sizeof(RGB2);
375 cbPalette = (1, pBHdr->biBitCount) * sizeof(RGB2);
376 break;
377
378 case 16:
379 case 32:
380 #ifdef BITFIELDS
381 if (pBHdr->biCompression == BI_BITFIELDS)
382 {
383 cbPalette = 3* sizeof(DWORD);
384 break;
385 }
386 #endif
387 case 24:
388 /* docs have it that there may be a palette used for optmizing processing of 16, 24 and 32 bits bitmaps */
389 /* the size of the palette is contained in biClrUsed - don't know if it stored as number of colors or as bytes... */
390 cbPalette = pBHdr->biClrUsed; //size in bytes or in (*sizeof(RGB2))?
391 break;
392
393 default:
394 dprintf(("QueryPaletteSize: error pBHdr->biBitCount = %d", pBHdr->biBitCount));
395 cbPalette = -1;
396 }
397
398 return cbPalette;
399}
400//******************************************************************************
401//******************************************************************************
402static ULONG QueryPaletteSize(BITMAPINFOHEADER *pBHdr)
403{
404 ULONG cbPalette;
405
406 switch (pBHdr->cBitCount)
407 {
408 case 1:
409 case 4:
410 case 8:
411 cbPalette = (1, pBHdr->cBitCount) * sizeof(RGB);
412 break;
413
414 case 16:
415 case 24:
416 case 32:
417 cbPalette = 0;
418 break;
419
420 default:
421 dprintf(("QueryPaletteSize: error pBHdr->biBitCount = %d", pBHdr->cBitCount));
422 cbPalette = -1;
423 }
424
425 return cbPalette;
426}
427//******************************************************************************
428//******************************************************************************
429static ULONG QueryPaletteSize(BITMAPINFOHEADER2 *pBHdr)
430{
431 ULONG cbPalette;
432
433 switch (pBHdr->cBitCount)
434 {
435 case 1:
436 case 4:
437 case 8:
438 cbPalette = ((pBHdr->cclrUsed != 0) ? pBHdr->cclrUsed : 1, pBHdr->cBitCount) * sizeof(RGB2);
439 //cbPalette = (1, pBHdr->cBitCount) * sizeof(RGB2);
440 break;
441
442 case 16:
443 case 32:
444 case 24:
445 /* docs have it that there may be a palette used for optmizing processing of 16, 24 and 32 bits bitmaps */
446 /* the size of the palette is contained in biClrUsed - don't know if it stored as number of colors or as bytes... */
447 cbPalette = pBHdr->cclrUsed; //size in bytes or in (*sizeof(RGB2))?
448 break;
449
450 default:
451 dprintf(("QueryPaletteSize: error pBHdr->biBitCount = %d", pBHdr->cBitCount));
452 cbPalette = -1;
453 }
454
455 return cbPalette;
456}
457//******************************************************************************
458//******************************************************************************
459static ULONG CalcBitmapSize(ULONG cBits, LONG cx, LONG cy)
460{
461 ULONG alignment;
462 ULONG factor;
463 BOOL flag = TRUE; //true: '*' false: '/'
464
465 cy = cy < 0 ? -cy : cy;
466
467 switch(cBits)
468 {
469 case 1:
470 factor = 8;
471 flag = FALSE;
472 break;
473
474 case 4:
475 factor = 2;
476 flag = FALSE;
477 break;
478
479 case 8:
480 factor = 1;
481 break;
482
483 case 16:
484 factor = 2;
485 break;
486
487 case 24:
488 factor = 3;
489 break;
490
491 case 32:
492 return cx*cy;
493
494 default:
495 return 0;
496 }
497
498 if (flag)
499 alignment = (cx = (cx*factor)) % 4;
500 else
501 alignment = (cx = ((cx+factor-1)/factor)) % 4;
502
503 if (alignment != 0)
504 cx += 4 - alignment;
505
506 return cx*cy;
507}
508//******************************************************************************
509//******************************************************************************
510ULONG QueryConvertedBitmapSize(WINBITMAPINFOHEADER *pBHdr, ULONG ulSize)
511{
512 ULONG retSize;
513 ltassert((ULONG)pBHdr > MINPTR && (ULONG)pBHdr+ulSize < MAXPTR);
514
515 switch (pBHdr->biSize)
516 {
517 /**************************************/
518 /* Windows v3.0 bitmap */
519 /**************************************/
520 case sizeof(WINBITMAPINFOHEADER):
521 {//convert to OS/2 v2.0 bitmap
522#ifdef BITFIELDS
523 if (pBHdr->biCompression == BI_RGB || pBHdr->biCompression == BI_BITFIELDS)
524#else
525 if (pBHdr->biCompression == BI_RGB)
526#endif
527 {
528 if (Need1BitTo4BitConvertWIN(pBHdr))
529 retSize = CalcBitmapSize(4, pBHdr->biWidth, pBHdr->biHeight);
530 else retSize = CalcBitmapSize(pBHdr->biBitCount, pBHdr->biWidth, pBHdr->biHeight);
531 }
532 else
533 {
534 retSize = pBHdr->biSizeImage;
535 if (retSize == 0)
536 retSize = ulSize - sizeof(WINBITMAPINFOHEADER) + sizeof(BITMAPFILEHEADER2);
537 }
538 ltassert(retSize != 0);
539
540 ULONG a = QueryPaletteSize(pBHdr);
541 ltassert(a != -1);
542 retSize += sizeof(BITMAPFILEHEADER2) + a;
543 break;
544 }
545
546 /**************************************/
547 /* Windows v4.0 bitmap */
548 /**************************************/
549 case sizeof(BITMAPV4HEADER):
550 {//convert to OS/2 v2.0 bitmap - some other day when I find the specs.
551 ltassert(FALSE && "Windows v4.0 bitmap");
552 break;
553 }
554
555 /**************************************/
556 /* OS/2 v1.x bitmap */
557 /**************************************/
558 case sizeof(BITMAPINFOHEADER):
559 {//no conversion needed - only build fileheader
560 PBITMAPINFOHEADER pBIH = (PBITMAPINFOHEADER)pBHdr;
561
562 if (Need1BitTo4BitConvertOS2(pBIH))
563 {
564 retSize = CalcBitmapSize(4, pBIH->cx, pBIH->cy);
565 ltassert(retSize != 0);
566
567 retSize += sizeof(RGB)*16; //palette
568 }
569 else
570 {
571 retSize = CalcBitmapSize(pBIH->cBitCount, pBIH->cx, pBIH->cy);
572 ltassert(retSize != 0);
573
574 ULONG a = QueryPaletteSize(pBIH);
575 ltassert(a != -1);
576 retSize += a;
577 }
578
579 retSize += sizeof(BITMAPFILEHEADER);
580 }
581
582 /**************************************/
583 /* OS/2 v2.0 bitmap - highly unlikely!*/
584 /**************************************/
585 case sizeof(BITMAPINFOHEADER2):
586 {//no conversion needed - only build fileheader
587 return ulSize + sizeof(BITMAPFILEHEADER2) - sizeof(BITMAPINFOHEADER2);
588 }
589
590 /**************************************/
591 /* Unknown */
592 /**************************************/
593 default: //fail
594 dprintf(("QueryConvertedBitmapSize - default - fail!"));
595 return 0;
596 }
597
598 return retSize;
599}
600//******************************************************************************
601//******************************************************************************
Note: See TracBrowser for help on using the repository browser.