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