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