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

Last change on this file since 1036 was 816, checked in by sandervl, 26 years ago

icongroup & cursorgroup fixes

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