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