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