]> git.saurik.com Git - wxWidgets.git/blob - src/msw/dibutils.cpp
IsModified() function now works correctly
[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 h = FindResourceA(GetCurrentInstance(), szFile, RT_BITMAP);
177
178 #if defined(WIN32) || defined(_WIN32)
179 //!!! can we call GlobalFree() on this? is it the right format.
180 //!!! can we write to this resource?
181 if (h)
182 return (PDIB)LockResource(LoadResource(GetCurrentInstance(), h));
183 #else
184 if (h)
185 fh = AccessResource(GetCurrentInstance(), h);
186 #endif
187 }
188
189 if (fh == -1)
190 return NULL;
191
192 pdib = DibReadBitmapInfo(fh);
193
194 if (!pdib)
195 return NULL;
196
197 /* How much memory do we need to hold the DIB */
198
199 dwBits = pdib->biSizeImage;
200 dwLen = pdib->biSize + DibPaletteSize(pdib) + dwBits;
201
202 /* Can we get more memory? */
203
204 p = GlobalReAllocPtr(pdib,dwLen,0);
205
206 if (!p)
207 {
208 GlobalFreePtr(pdib);
209 pdib = NULL;
210 }
211 else
212 {
213 pdib = (PDIB)p;
214 }
215
216 if (pdib)
217 {
218 /* read in the bits */
219 _hread(fh, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits);
220 }
221
222 _lclose(fh);
223
224 return pdib;
225 }
226
227
228 /*
229 * ReadDibBitmapInfo()
230 *
231 * Will read a file in DIB format and return a global HANDLE to its
232 * BITMAPINFO. This function will work with both "old" and "new"
233 * bitmap formats, but will always return a "new" BITMAPINFO.
234 */
235
236 PDIB DibReadBitmapInfo(HFILE fh)
237 {
238 DWORD off;
239 HANDLE hbi = NULL;
240 int size;
241 int i;
242 int nNumColors;
243
244 RGBQUAD FAR *pRgb;
245 BITMAPINFOHEADER bi;
246 BITMAPCOREHEADER bc;
247 BITMAPFILEHEADER bf;
248 PDIB pdib;
249
250 if (fh == -1)
251 return NULL;
252
253 off = _llseek(fh,0L,SEEK_CUR);
254
255 if (sizeof(bf) != _lread(fh,(LPSTR)&bf,sizeof(bf)))
256 return FALSE;
257
258 /*
259 * do we have a RC HEADER?
260 */
261 if (bf.bfType != BFT_BITMAP)
262 {
263 bf.bfOffBits = 0L;
264 _llseek(fh,off,SEEK_SET);
265 }
266
267 if (sizeof(bi) != _lread(fh,(LPSTR)&bi,sizeof(bi)))
268 return FALSE;
269
270 /*
271 * what type of bitmap info is this?
272 */
273 switch (size = (int)bi.biSize)
274 {
275 default:
276 case sizeof(BITMAPINFOHEADER):
277 break;
278
279 case sizeof(BITMAPCOREHEADER):
280 bc = *(BITMAPCOREHEADER*)&bi;
281 bi.biSize = sizeof(BITMAPINFOHEADER);
282 bi.biWidth = (DWORD)bc.bcWidth;
283 bi.biHeight = (DWORD)bc.bcHeight;
284 bi.biPlanes = (UINT)bc.bcPlanes;
285 bi.biBitCount = (UINT)bc.bcBitCount;
286 bi.biCompression = BI_RGB;
287 bi.biSizeImage = 0;
288 bi.biXPelsPerMeter = 0;
289 bi.biYPelsPerMeter = 0;
290 bi.biClrUsed = 0;
291 bi.biClrImportant = 0;
292
293 _llseek(fh,(LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER),SEEK_CUR);
294
295 break;
296 }
297
298 nNumColors = DibNumColors(&bi);
299
300 #if 0
301 if (bi.biSizeImage == 0)
302 bi.biSizeImage = DibSizeImage(&bi);
303
304 if (bi.biClrUsed == 0)
305 bi.biClrUsed = DibNumColors(&bi);
306 #else
307 FixBitmapInfo(&bi);
308 #endif
309
310 pdib = (PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
311
312 if (!pdib)
313 return NULL;
314
315 *pdib = bi;
316
317 pRgb = DibColors(pdib);
318
319 if (nNumColors)
320 {
321 if (size == sizeof(BITMAPCOREHEADER))
322 {
323 /*
324 * convert a old color table (3 byte entries) to a new
325 * color table (4 byte entries)
326 */
327 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBTRIPLE));
328
329 for (i=nNumColors-1; i>=0; i--)
330 {
331 RGBQUAD rgb;
332
333 rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
334 rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
335 rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
336 rgb.rgbReserved = (BYTE)0;
337
338 pRgb[i] = rgb;
339 }
340 }
341 else
342 {
343 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBQUAD));
344 }
345 }
346
347 if (bf.bfOffBits != 0L)
348 _llseek(fh,off + bf.bfOffBits,SEEK_SET);
349
350 return pdib;
351 }
352
353 /*
354 * DibSetUsage(hdib,hpal,wUsage)
355 *
356 * Modifies the color table of the passed DIB for use with the wUsage
357 * parameter specifed.
358 *
359 * if wUsage is DIB_PAL_COLORS the DIB color table is set to 0-256
360 * if wUsage is DIB_RGB_COLORS the DIB color table is set to the RGB values
361 * in the passed palette
362 */
363
364 BOOL DibSetUsage(PDIB pdib, HPALETTE hpal,UINT wUsage)
365 {
366 PALETTEENTRY ape[256];
367 RGBQUAD FAR * pRgb;
368 WORD FAR * pw;
369 int nColors;
370 int n;
371
372 if (hpal == NULL)
373 hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
374
375 if (!pdib)
376 return FALSE;
377
378 nColors = DibNumColors(pdib);
379
380 if (nColors == 3 && DibCompression(pdib) == BI_BITFIELDS)
381 nColors = 0;
382
383 if (nColors > 0)
384 {
385 pRgb = DibColors(pdib);
386
387 switch (wUsage)
388 {
389 //
390 // Set the DIB color table to palette indexes
391 //
392 case DIB_PAL_COLORS:
393 for (pw = (WORD FAR*)pRgb,n=0; n<nColors; n++,pw++)
394 *pw = n;
395 break;
396
397 //
398 // Set the DIB color table to RGBQUADS
399 //
400 default:
401 case DIB_RGB_COLORS:
402 nColors = (nColors < 256) ? nColors: 256;
403
404 GetPaletteEntries(hpal,0,nColors,ape);
405
406 for (n=0; n<nColors; n++)
407 {
408 pRgb[n].rgbRed = ape[n].peRed;
409 pRgb[n].rgbGreen = ape[n].peGreen;
410 pRgb[n].rgbBlue = ape[n].peBlue;
411 pRgb[n].rgbReserved = 0;
412 }
413 break;
414 }
415 }
416 return TRUE;
417 }
418
419 /*
420 * DibCreate(bits, dx, dy)
421 *
422 * Creates a new packed DIB with the given dimensions and the
423 * given number of bits per pixel
424 */
425
426 PDIB DibCreate(int bits, int dx, int dy)
427 {
428 LPBITMAPINFOHEADER lpbi ;
429 DWORD dwSizeImage;
430 int i;
431 DWORD FAR *pdw;
432
433 dwSizeImage = dy*(DWORD)((dx*bits/8+3)&~3);
434
435 lpbi = (PDIB)GlobalAllocPtr(GHND,sizeof(BITMAPINFOHEADER)+dwSizeImage + 1024);
436
437 if (lpbi == NULL)
438 return NULL;
439
440 lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
441 lpbi->biWidth = dx;
442 lpbi->biHeight = dy;
443 lpbi->biPlanes = 1;
444 lpbi->biBitCount = bits ;
445 lpbi->biCompression = BI_RGB ;
446 lpbi->biSizeImage = dwSizeImage;
447 lpbi->biXPelsPerMeter = 0 ;
448 lpbi->biYPelsPerMeter = 0 ;
449 lpbi->biClrUsed = 0 ;
450 lpbi->biClrImportant = 0 ;
451
452 if (bits == 4)
453 lpbi->biClrUsed = 16;
454
455 else if (bits == 8)
456 lpbi->biClrUsed = 256;
457
458 pdw = (DWORD FAR *)((LPBYTE)lpbi+(int)lpbi->biSize);
459
460 for (i=0; i<(int)lpbi->biClrUsed/16; i++)
461 {
462 *pdw++ = 0x00000000; // 0000 black
463 *pdw++ = 0x00800000; // 0001 dark red
464 *pdw++ = 0x00008000; // 0010 dark green
465 *pdw++ = 0x00808000; // 0011 mustard
466 *pdw++ = 0x00000080; // 0100 dark blue
467 *pdw++ = 0x00800080; // 0101 purple
468 *pdw++ = 0x00008080; // 0110 dark turquoise
469 *pdw++ = 0x00C0C0C0; // 1000 gray
470 *pdw++ = 0x00808080; // 0111 dark gray
471 *pdw++ = 0x00FF0000; // 1001 red
472 *pdw++ = 0x0000FF00; // 1010 green
473 *pdw++ = 0x00FFFF00; // 1011 yellow
474 *pdw++ = 0x000000FF; // 1100 blue
475 *pdw++ = 0x00FF00FF; // 1101 pink (magenta)
476 *pdw++ = 0x0000FFFF; // 1110 cyan
477 *pdw++ = 0x00FFFFFF; // 1111 white
478 }
479
480 return (PDIB)lpbi;
481 }
482
483 static void xlatClut8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
484 {
485 DWORD dw;
486
487 #ifdef __cplusplus
488 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
489 #else
490 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
491 #endif
492 *pb = xlat[*pb];
493 }
494
495 static void xlatClut4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
496 {
497 DWORD dw;
498
499 #ifdef __cplusplus
500 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
501 #else
502 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
503 #endif
504 *pb = (BYTE)(xlat[*pb & 0x0F] | (xlat[(*pb >> 4) & 0x0F] << 4));
505 }
506
507 #define RLE_ESCAPE 0
508 #define RLE_EOL 0
509 #define RLE_EOF 1
510 #define RLE_JMP 2
511
512 static void xlatRle8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
513 {
514 BYTE cnt;
515 BYTE b;
516 BYTE _huge *prle = pb;
517
518 for(;;)
519 {
520 cnt = *prle++;
521 b = *prle;
522
523 if (cnt == RLE_ESCAPE)
524 {
525 prle++;
526
527 switch (b)
528 {
529 case RLE_EOF:
530 return;
531
532 case RLE_EOL:
533 break;
534
535 case RLE_JMP:
536 prle++; // skip dX
537 prle++; // skip dY
538 break;
539
540 default:
541 cnt = b;
542 for (b=0; b<cnt; b++,prle++)
543 *prle = xlat[*prle];
544
545 if (cnt & 1)
546 prle++;
547
548 break;
549 }
550 }
551 else
552 {
553 *prle++ = xlat[b];
554 }
555 }
556 }
557
558 static void xlatRle4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
559 {
560 }
561
562 static void hmemmove(BYTE _huge *d, BYTE _huge *s, LONG len)
563 {
564 d += len-1;
565 s += len-1;
566
567 while (len--)
568 *d-- = *s--;
569 }
570
571 /*
572 * DibMapToPalette(pdib, hpal)
573 *
574 * Map the colors of the DIB, using GetNearestPaletteIndex, to
575 * the colors of the given palette.
576 */
577
578 BOOL DibMapToPalette(PDIB pdib, HPALETTE hpal)
579 {
580 LPBITMAPINFOHEADER lpbi;
581 PALETTEENTRY pe;
582 int n;
583 int nDibColors;
584 int nPalColors=0;
585 BYTE FAR * lpBits;
586 RGBQUAD FAR * lpRgb;
587 BYTE xlat[256];
588 DWORD SizeImage;
589
590 if (!hpal || !pdib)
591 return FALSE;
592
593 lpbi = (LPBITMAPINFOHEADER)pdib;
594 lpRgb = DibColors(pdib);
595
596 GetObject(hpal,sizeof(int),(LPSTR)&nPalColors);
597 nDibColors = DibNumColors(pdib);
598
599 if ((SizeImage = lpbi->biSizeImage) == 0)
600 SizeImage = DibSizeImage(lpbi);
601
602 //
603 // build a xlat table. from the current DIB colors to the given
604 // palette.
605 //
606 for (n=0; n<nDibColors; n++)
607 xlat[n] = (BYTE)GetNearestPaletteIndex(hpal,RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
608
609 lpBits = (LPBYTE)DibPtr(lpbi);
610 lpbi->biClrUsed = nPalColors;
611
612 //
613 // re-size the DIB
614 //
615 if (nPalColors > nDibColors)
616 {
617 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
618 hmemmove((BYTE _huge *)DibPtr(lpbi), (BYTE _huge *)lpBits, SizeImage);
619 lpBits = (LPBYTE)DibPtr(lpbi);
620 }
621 else if (nPalColors < nDibColors)
622 {
623 hmemcpy(DibPtr(lpbi), lpBits, SizeImage);
624 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
625 lpBits = (LPBYTE)DibPtr(lpbi);
626 }
627
628 //
629 // translate the DIB bits
630 //
631 switch (lpbi->biCompression)
632 {
633 case BI_RLE8:
634 xlatRle8(lpBits, SizeImage, xlat);
635 break;
636
637 case BI_RLE4:
638 xlatRle4(lpBits, SizeImage, xlat);
639 break;
640
641 case BI_RGB:
642 if (lpbi->biBitCount == 8)
643 xlatClut8(lpBits, SizeImage, xlat);
644 else
645 xlatClut4(lpBits, SizeImage, xlat);
646 break;
647 }
648
649 //
650 // Now copy the RGBs in the logical palette to the dib color table
651 //
652 for (n=0; n<nPalColors; n++)
653 {
654 GetPaletteEntries(hpal,n,1,&pe);
655
656 lpRgb[n].rgbRed = pe.peRed;
657 lpRgb[n].rgbGreen = pe.peGreen;
658 lpRgb[n].rgbBlue = pe.peBlue;
659 lpRgb[n].rgbReserved = (BYTE)0;
660 }
661
662 return TRUE;
663 }
664
665
666 HPALETTE MakePalette(const BITMAPINFO FAR* Info, UINT flags)
667 {
668 HPALETTE hPalette;
669 const RGBQUAD far* rgb = Info->bmiColors;
670
671 WORD nColors = Info->bmiHeader.biClrUsed;
672 if (nColors) {
673 LOGPALETTE* logPal = (LOGPALETTE*)
674 new BYTE[sizeof(LOGPALETTE) + (nColors-1)*sizeof(PALETTEENTRY)];
675
676 logPal->palVersion = 0x300; // Windows 3.0 version
677 logPal->palNumEntries = nColors;
678 for (short n = 0; n < nColors; n++) {
679 logPal->palPalEntry[n].peRed = rgb[n].rgbRed;
680 logPal->palPalEntry[n].peGreen = rgb[n].rgbGreen;
681 logPal->palPalEntry[n].peBlue = rgb[n].rgbBlue;
682 logPal->palPalEntry[n].peFlags = (BYTE)flags;
683 }
684 hPalette = ::CreatePalette(logPal);
685 delete logPal;
686 } else
687 hPalette = 0;
688
689 return hPalette;
690 }
691