]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dibutils.cpp
Changes for 16-bit BC++ (not there yet), GnuWin32; typetest sample
[wxWidgets.git] / src / msw / dibutils.cpp
1 /////////////////////////////////////////////////////////////////////////////
2 // Name: dibutils.cpp
3 // Purpose: Utilities for DIBs
4 // Author: Julian Smart
5 // Modified by:
6 // Created: 04/01/98
7 // RCS-ID: $Id$
8 // Copyright: (c) Microsoft, Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
11
12 #ifdef __GNUG__
13 #pragma implementation "dibutils.h"
14 #endif
15
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
18
19 #ifdef __BORLANDC__
20 #pragma hdrstop
21 #endif
22
23 #ifndef WX_PRECOMP
24 #include <stdio.h>
25 #include "wx/setup.h"
26 #include "wx/defs.h"
27 #endif
28
29 #include <windows.h>
30 #include <windowsx.h>
31 #include <stdio.h>
32 #include <wx/msw/dibutils.h>
33
34 #if defined(__WIN32__)
35 #include <memory.h> // for _fmemcpy()
36 #define _huge
37 #ifndef hmemcpy
38 #define hmemcpy memcpy
39 #endif
40 #endif
41
42 #define BFT_ICON 0x4349 /* 'IC' */
43 #define BFT_BITMAP 0x4d42 /* 'BM' */
44 #define BFT_CURSOR 0x5450 /* 'PT' */
45
46 /* flags for _lseek */
47 #define SEEK_CUR 1
48 #define SEEK_END 2
49 #define SEEK_SET 0
50
51
52 /*
53 * Clear the System Palette so that we can ensure an identity palette
54 * mapping for fast performance.
55 */
56
57 void ClearSystemPalette(void)
58 {
59 //*** A dummy palette setup
60 struct
61 {
62 WORD Version;
63 WORD NumberOfEntries;
64 PALETTEENTRY aEntries[256];
65 } Palette =
66 {
67 0x300,
68 256
69 };
70
71 HPALETTE ScreenPalette = 0;
72 HDC ScreenDC;
73 int Counter;
74 UINT nMapped = 0;
75 BOOL bOK = FALSE;
76 int nOK = 0;
77
78 //*** Reset everything in the system palette to black
79 for(Counter = 0; Counter < 256; Counter++)
80 {
81 Palette.aEntries[Counter].peRed = 0;
82 Palette.aEntries[Counter].peGreen = 0;
83 Palette.aEntries[Counter].peBlue = 0;
84 Palette.aEntries[Counter].peFlags = PC_NOCOLLAPSE;
85 }
86
87 //*** Create, select, realize, deselect, and delete the palette
88 ScreenDC = GetDC(NULL);
89 ScreenPalette = CreatePalette((LOGPALETTE *)&Palette);
90
91 if (ScreenPalette)
92 {
93 ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
94 nMapped = RealizePalette(ScreenDC);
95 ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
96 bOK = DeleteObject(ScreenPalette);
97 }
98
99 nOK = ReleaseDC(NULL, ScreenDC);
100
101 return;
102 }
103
104
105 /*
106 * Open a DIB file and return a MEMORY DIB, a memory handle containing..
107 *
108 * BITMAP INFO bi
109 * palette data
110 * bits....
111 */
112
113 int DibWriteFile(LPSTR szFile, LPBITMAPINFOHEADER lpbi)
114 {
115 HFILE fh;
116 OFSTRUCT of;
117
118 fh = OpenFile(szFile, &of, OF_WRITE | OF_CREATE);
119
120 if (!fh) {
121 // printf("la regamos0");
122 return 0;
123 }
124
125 long size = DibSize(lpbi);
126
127 // write file header
128 BITMAPFILEHEADER bmf;
129 bmf.bfType = 'BM';
130 bmf.bfSize = sizeof(bmf) + size;
131 bmf.bfReserved1 = 0;
132 bmf.bfReserved2 = 0;
133 bmf.bfOffBits = sizeof(bmf) + (char far*)(DibPtr(lpbi)) - (char far*)lpbi;
134 #if defined( __WATCOMC__) || defined(_MSC_VER)
135 if (_hwrite(fh, (LPCSTR)(&bmf), sizeof(bmf))<0 ||
136 _hwrite(fh, (LPCSTR)lpbi, size)<0) {
137 _lclose(fh);
138 // printf("la regamos1");
139 return 0;
140 }
141 #else
142 if (_hwrite(fh, (LPBYTE)(&bmf), sizeof(bmf))<0 ||
143 _hwrite(fh, (LPBYTE)lpbi, size)<0) {
144 _lclose(fh);
145 // printf("la regamos1");
146 return 0;
147 }
148 #endif
149
150 _lclose(fh);
151 return 1;
152 }
153
154 PDIB DibOpenFile(LPSTR szFile)
155 {
156 HFILE fh;
157 DWORD dwLen;
158 DWORD dwBits;
159 PDIB pdib;
160 LPVOID p;
161 OFSTRUCT of;
162
163 #if defined(WIN32) || defined(_WIN32)
164 #define GetCurrentInstance() GetModuleHandle(NULL)
165 #else
166 #define GetCurrentInstance() (HINSTANCE)SELECTOROF((LPVOID)&of)
167 #endif
168
169 fh = OpenFile(szFile, &of, OF_READ);
170
171 if (fh == -1)
172 {
173 HRSRC h;
174
175 // TODO: Unicode version
176 #ifdef __WIN16__
177 h = FindResource(GetCurrentInstance(), szFile, RT_BITMAP);
178 #else
179 h = FindResourceA(GetCurrentInstance(), szFile, RT_BITMAP);
180 #endif
181
182 #if defined(__WIN32__)
183 //!!! can we call GlobalFree() on this? is it the right format.
184 //!!! can we write to this resource?
185 if (h)
186 return (PDIB)LockResource(LoadResource(GetCurrentInstance(), h));
187 #else
188 if (h)
189 fh = AccessResource(GetCurrentInstance(), h);
190 #endif
191 }
192
193 if (fh == -1)
194 return NULL;
195
196 pdib = DibReadBitmapInfo(fh);
197
198 if (!pdib)
199 return NULL;
200
201 /* How much memory do we need to hold the DIB */
202
203 dwBits = pdib->biSizeImage;
204 dwLen = pdib->biSize + DibPaletteSize(pdib) + dwBits;
205
206 /* Can we get more memory? */
207
208 p = GlobalReAllocPtr(pdib,dwLen,0);
209
210 if (!p)
211 {
212 GlobalFreePtr(pdib);
213 pdib = NULL;
214 }
215 else
216 {
217 pdib = (PDIB)p;
218 }
219
220 if (pdib)
221 {
222 /* read in the bits */
223 _hread(fh, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits);
224 }
225
226 _lclose(fh);
227
228 return pdib;
229 }
230
231
232 /*
233 * ReadDibBitmapInfo()
234 *
235 * Will read a file in DIB format and return a global HANDLE to its
236 * BITMAPINFO. This function will work with both "old" and "new"
237 * bitmap formats, but will always return a "new" BITMAPINFO.
238 */
239
240 PDIB DibReadBitmapInfo(HFILE fh)
241 {
242 DWORD off;
243 HANDLE hbi = NULL;
244 int size;
245 int i;
246 int nNumColors;
247
248 RGBQUAD FAR *pRgb;
249 BITMAPINFOHEADER bi;
250 BITMAPCOREHEADER bc;
251 BITMAPFILEHEADER bf;
252 PDIB pdib;
253
254 if (fh == -1)
255 return NULL;
256
257 off = _llseek(fh,0L,SEEK_CUR);
258
259 if (sizeof(bf) != _lread(fh,(LPSTR)&bf,sizeof(bf)))
260 return FALSE;
261
262 /*
263 * do we have a RC HEADER?
264 */
265 if (bf.bfType != BFT_BITMAP)
266 {
267 bf.bfOffBits = 0L;
268 _llseek(fh,off,SEEK_SET);
269 }
270
271 if (sizeof(bi) != _lread(fh,(LPSTR)&bi,sizeof(bi)))
272 return FALSE;
273
274 /*
275 * what type of bitmap info is this?
276 */
277 switch (size = (int)bi.biSize)
278 {
279 default:
280 case sizeof(BITMAPINFOHEADER):
281 break;
282
283 case sizeof(BITMAPCOREHEADER):
284 bc = *(BITMAPCOREHEADER*)&bi;
285 bi.biSize = sizeof(BITMAPINFOHEADER);
286 bi.biWidth = (DWORD)bc.bcWidth;
287 bi.biHeight = (DWORD)bc.bcHeight;
288 bi.biPlanes = (UINT)bc.bcPlanes;
289 bi.biBitCount = (UINT)bc.bcBitCount;
290 bi.biCompression = BI_RGB;
291 bi.biSizeImage = 0;
292 bi.biXPelsPerMeter = 0;
293 bi.biYPelsPerMeter = 0;
294 bi.biClrUsed = 0;
295 bi.biClrImportant = 0;
296
297 _llseek(fh,(LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER),SEEK_CUR);
298
299 break;
300 }
301
302 nNumColors = DibNumColors(&bi);
303
304 #if 0
305 if (bi.biSizeImage == 0)
306 bi.biSizeImage = DibSizeImage(&bi);
307
308 if (bi.biClrUsed == 0)
309 bi.biClrUsed = DibNumColors(&bi);
310 #else
311 FixBitmapInfo(&bi);
312 #endif
313
314 pdib = (PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
315
316 if (!pdib)
317 return NULL;
318
319 *pdib = bi;
320
321 pRgb = DibColors(pdib);
322
323 if (nNumColors)
324 {
325 if (size == sizeof(BITMAPCOREHEADER))
326 {
327 /*
328 * convert a old color table (3 byte entries) to a new
329 * color table (4 byte entries)
330 */
331 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBTRIPLE));
332
333 for (i=nNumColors-1; i>=0; i--)
334 {
335 RGBQUAD rgb;
336
337 rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
338 rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
339 rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
340 rgb.rgbReserved = (BYTE)0;
341
342 pRgb[i] = rgb;
343 }
344 }
345 else
346 {
347 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBQUAD));
348 }
349 }
350
351 if (bf.bfOffBits != 0L)
352 _llseek(fh,off + bf.bfOffBits,SEEK_SET);
353
354 return pdib;
355 }
356
357 /*
358 * DibSetUsage(hdib,hpal,wUsage)
359 *
360 * Modifies the color table of the passed DIB for use with the wUsage
361 * parameter specifed.
362 *
363 * if wUsage is DIB_PAL_COLORS the DIB color table is set to 0-256
364 * if wUsage is DIB_RGB_COLORS the DIB color table is set to the RGB values
365 * in the passed palette
366 */
367
368 BOOL DibSetUsage(PDIB pdib, HPALETTE hpal,UINT wUsage)
369 {
370 PALETTEENTRY ape[256];
371 RGBQUAD FAR * pRgb;
372 WORD FAR * pw;
373 int nColors;
374 int n;
375
376 if (hpal == NULL)
377 hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
378
379 if (!pdib)
380 return FALSE;
381
382 nColors = DibNumColors(pdib);
383
384 if (nColors == 3 && DibCompression(pdib) == BI_BITFIELDS)
385 nColors = 0;
386
387 if (nColors > 0)
388 {
389 pRgb = DibColors(pdib);
390
391 switch (wUsage)
392 {
393 //
394 // Set the DIB color table to palette indexes
395 //
396 case DIB_PAL_COLORS:
397 for (pw = (WORD FAR*)pRgb,n=0; n<nColors; n++,pw++)
398 *pw = n;
399 break;
400
401 //
402 // Set the DIB color table to RGBQUADS
403 //
404 default:
405 case DIB_RGB_COLORS:
406 nColors = (nColors < 256) ? nColors: 256;
407
408 GetPaletteEntries(hpal,0,nColors,ape);
409
410 for (n=0; n<nColors; n++)
411 {
412 pRgb[n].rgbRed = ape[n].peRed;
413 pRgb[n].rgbGreen = ape[n].peGreen;
414 pRgb[n].rgbBlue = ape[n].peBlue;
415 pRgb[n].rgbReserved = 0;
416 }
417 break;
418 }
419 }
420 return TRUE;
421 }
422
423 /*
424 * DibCreate(bits, dx, dy)
425 *
426 * Creates a new packed DIB with the given dimensions and the
427 * given number of bits per pixel
428 */
429
430 PDIB DibCreate(int bits, int dx, int dy)
431 {
432 LPBITMAPINFOHEADER lpbi ;
433 DWORD dwSizeImage;
434 int i;
435 DWORD FAR *pdw;
436
437 dwSizeImage = dy*(DWORD)((dx*bits/8+3)&~3);
438
439 lpbi = (PDIB)GlobalAllocPtr(GHND,sizeof(BITMAPINFOHEADER)+dwSizeImage + 1024);
440
441 if (lpbi == NULL)
442 return NULL;
443
444 lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
445 lpbi->biWidth = dx;
446 lpbi->biHeight = dy;
447 lpbi->biPlanes = 1;
448 lpbi->biBitCount = bits ;
449 lpbi->biCompression = BI_RGB ;
450 lpbi->biSizeImage = dwSizeImage;
451 lpbi->biXPelsPerMeter = 0 ;
452 lpbi->biYPelsPerMeter = 0 ;
453 lpbi->biClrUsed = 0 ;
454 lpbi->biClrImportant = 0 ;
455
456 if (bits == 4)
457 lpbi->biClrUsed = 16;
458
459 else if (bits == 8)
460 lpbi->biClrUsed = 256;
461
462 pdw = (DWORD FAR *)((LPBYTE)lpbi+(int)lpbi->biSize);
463
464 for (i=0; i<(int)lpbi->biClrUsed/16; i++)
465 {
466 *pdw++ = 0x00000000; // 0000 black
467 *pdw++ = 0x00800000; // 0001 dark red
468 *pdw++ = 0x00008000; // 0010 dark green
469 *pdw++ = 0x00808000; // 0011 mustard
470 *pdw++ = 0x00000080; // 0100 dark blue
471 *pdw++ = 0x00800080; // 0101 purple
472 *pdw++ = 0x00008080; // 0110 dark turquoise
473 *pdw++ = 0x00C0C0C0; // 1000 gray
474 *pdw++ = 0x00808080; // 0111 dark gray
475 *pdw++ = 0x00FF0000; // 1001 red
476 *pdw++ = 0x0000FF00; // 1010 green
477 *pdw++ = 0x00FFFF00; // 1011 yellow
478 *pdw++ = 0x000000FF; // 1100 blue
479 *pdw++ = 0x00FF00FF; // 1101 pink (magenta)
480 *pdw++ = 0x0000FFFF; // 1110 cyan
481 *pdw++ = 0x00FFFFFF; // 1111 white
482 }
483
484 return (PDIB)lpbi;
485 }
486
487 static void xlatClut8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
488 {
489 DWORD dw;
490
491 #ifdef __cplusplus
492 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
493 #else
494 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
495 #endif
496 *pb = xlat[*pb];
497 }
498
499 static void xlatClut4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
500 {
501 DWORD dw;
502
503 #ifdef __cplusplus
504 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
505 #else
506 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
507 #endif
508 *pb = (BYTE)(xlat[*pb & 0x0F] | (xlat[(*pb >> 4) & 0x0F] << 4));
509 }
510
511 #define RLE_ESCAPE 0
512 #define RLE_EOL 0
513 #define RLE_EOF 1
514 #define RLE_JMP 2
515
516 static void xlatRle8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
517 {
518 BYTE cnt;
519 BYTE b;
520 BYTE _huge *prle = pb;
521
522 for(;;)
523 {
524 cnt = *prle++;
525 b = *prle;
526
527 if (cnt == RLE_ESCAPE)
528 {
529 prle++;
530
531 switch (b)
532 {
533 case RLE_EOF:
534 return;
535
536 case RLE_EOL:
537 break;
538
539 case RLE_JMP:
540 prle++; // skip dX
541 prle++; // skip dY
542 break;
543
544 default:
545 cnt = b;
546 for (b=0; b<cnt; b++,prle++)
547 *prle = xlat[*prle];
548
549 if (cnt & 1)
550 prle++;
551
552 break;
553 }
554 }
555 else
556 {
557 *prle++ = xlat[b];
558 }
559 }
560 }
561
562 static void xlatRle4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
563 {
564 }
565
566 static void hmemmove(BYTE _huge *d, BYTE _huge *s, LONG len)
567 {
568 d += len-1;
569 s += len-1;
570
571 while (len--)
572 *d-- = *s--;
573 }
574
575 /*
576 * DibMapToPalette(pdib, hpal)
577 *
578 * Map the colors of the DIB, using GetNearestPaletteIndex, to
579 * the colors of the given palette.
580 */
581
582 BOOL DibMapToPalette(PDIB pdib, HPALETTE hpal)
583 {
584 LPBITMAPINFOHEADER lpbi;
585 PALETTEENTRY pe;
586 int n;
587 int nDibColors;
588 int nPalColors=0;
589 BYTE FAR * lpBits;
590 RGBQUAD FAR * lpRgb;
591 BYTE xlat[256];
592 DWORD SizeImage;
593
594 if (!hpal || !pdib)
595 return FALSE;
596
597 lpbi = (LPBITMAPINFOHEADER)pdib;
598 lpRgb = DibColors(pdib);
599
600 GetObject(hpal,sizeof(int),(LPSTR)&nPalColors);
601 nDibColors = DibNumColors(pdib);
602
603 if ((SizeImage = lpbi->biSizeImage) == 0)
604 SizeImage = DibSizeImage(lpbi);
605
606 //
607 // build a xlat table. from the current DIB colors to the given
608 // palette.
609 //
610 for (n=0; n<nDibColors; n++)
611 xlat[n] = (BYTE)GetNearestPaletteIndex(hpal,RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
612
613 lpBits = (LPBYTE)DibPtr(lpbi);
614 lpbi->biClrUsed = nPalColors;
615
616 //
617 // re-size the DIB
618 //
619 if (nPalColors > nDibColors)
620 {
621 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
622 hmemmove((BYTE _huge *)DibPtr(lpbi), (BYTE _huge *)lpBits, SizeImage);
623 lpBits = (LPBYTE)DibPtr(lpbi);
624 }
625 else if (nPalColors < nDibColors)
626 {
627 hmemcpy(DibPtr(lpbi), lpBits, SizeImage);
628 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
629 lpBits = (LPBYTE)DibPtr(lpbi);
630 }
631
632 //
633 // translate the DIB bits
634 //
635 switch (lpbi->biCompression)
636 {
637 case BI_RLE8:
638 xlatRle8(lpBits, SizeImage, xlat);
639 break;
640
641 case BI_RLE4:
642 xlatRle4(lpBits, SizeImage, xlat);
643 break;
644
645 case BI_RGB:
646 if (lpbi->biBitCount == 8)
647 xlatClut8(lpBits, SizeImage, xlat);
648 else
649 xlatClut4(lpBits, SizeImage, xlat);
650 break;
651 }
652
653 //
654 // Now copy the RGBs in the logical palette to the dib color table
655 //
656 for (n=0; n<nPalColors; n++)
657 {
658 GetPaletteEntries(hpal,n,1,&pe);
659
660 lpRgb[n].rgbRed = pe.peRed;
661 lpRgb[n].rgbGreen = pe.peGreen;
662 lpRgb[n].rgbBlue = pe.peBlue;
663 lpRgb[n].rgbReserved = (BYTE)0;
664 }
665
666 return TRUE;
667 }
668
669
670 HPALETTE MakePalette(const BITMAPINFO FAR* Info, UINT flags)
671 {
672 HPALETTE hPalette;
673 const RGBQUAD far* rgb = Info->bmiColors;
674
675 WORD nColors = Info->bmiHeader.biClrUsed;
676 if (nColors) {
677 LOGPALETTE* logPal = (LOGPALETTE*)
678 new BYTE[sizeof(LOGPALETTE) + (nColors-1)*sizeof(PALETTEENTRY)];
679
680 logPal->palVersion = 0x300; // Windows 3.0 version
681 logPal->palNumEntries = nColors;
682 for (short n = 0; n < nColors; n++) {
683 logPal->palPalEntry[n].peRed = rgb[n].rgbRed;
684 logPal->palPalEntry[n].peGreen = rgb[n].rgbGreen;
685 logPal->palPalEntry[n].peBlue = rgb[n].rgbBlue;
686 logPal->palPalEntry[n].peFlags = (BYTE)flags;
687 }
688 hPalette = ::CreatePalette(logPal);
689 delete logPal;
690 } else
691 hPalette = 0;
692
693 return hPalette;
694 }
695