1 /////////////////////////////////////////////////////////////////////////////
3 // Purpose: Utilities for DIBs
4 // Author: Julian Smart
8 // Copyright: (c) Microsoft, Julian Smart and Markus Holzem
9 // Licence: wxWindows license
10 /////////////////////////////////////////////////////////////////////////////
13 #pragma implementation "dibutils.h"
16 // For compilers that support precompilation, includes "wx.h".
17 #include "wx/wxprec.h"
26 #include "wx/string.h"
33 #include "wx/msw/dibutils.h"
39 #if defined(__WIN32__)
40 #if !defined(__MWERKS__) && !defined(__SALFORDC__)
41 #include <memory.h> // for _fmemcpy()
45 #define hmemcpy memcpy
49 #define BFT_ICON 0x4349 /* 'IC' */
50 #define BFT_BITMAP 0x4d42 /* 'BM' */
51 #define BFT_CURSOR 0x5450 /* 'PT' */
54 /* flags for _lseek */
60 /* Copied from PNGhandler for coompilation with MingW32, RR */
62 #ifndef GlobalAllocPtr
63 #define GlobalPtrHandle(lp) \
64 ((HGLOBAL)GlobalHandle(lp))
66 #define GlobalLockPtr(lp) \
67 ((BOOL)GlobalLock(GlobalPtrHandle(lp)))
68 #define GlobalUnlockPtr(lp) \
69 GlobalUnlock(GlobalPtrHandle(lp))
71 #define GlobalAllocPtr(flags, cb) \
72 (GlobalLock(GlobalAlloc((flags), (cb))))
73 #define GlobalReAllocPtr(lp, cbNew, flags) \
74 (GlobalUnlockPtr(lp), GlobalLock(GlobalReAlloc(GlobalPtrHandle(lp) , (cbNew), (flags))))
75 #define GlobalFreePtr(lp) \
76 (GlobalUnlockPtr(lp), (BOOL)GlobalFree(GlobalPtrHandle(lp)))
81 * Clear the System Palette so that we can ensure an identity palette
82 * mapping for fast performance.
85 void ClearSystemPalette(void)
87 //*** A dummy palette setup
92 PALETTEENTRY aEntries[256];
99 HPALETTE ScreenPalette = 0;
106 // *** Reset everything in the system palette to black
107 for(Counter = 0; Counter < 256; Counter++)
109 Palette.aEntries[Counter].peRed = 0;
110 Palette.aEntries[Counter].peGreen = 0;
111 Palette.aEntries[Counter].peBlue = 0;
112 Palette.aEntries[Counter].peFlags = PC_NOCOLLAPSE;
115 // *** Create, select, realize, deselect, and delete the palette
117 ScreenDC = GetDC((HWND)NULL);
119 ScreenDC = GetDC(NULL);
121 ScreenPalette = CreatePalette((LOGPALETTE *)&Palette);
125 ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
126 nMapped = RealizePalette(ScreenDC);
127 ScreenPalette = SelectPalette(ScreenDC,ScreenPalette,FALSE);
128 bOK = DeleteObject(ScreenPalette);
132 nOK = ReleaseDC((HWND)NULL, ScreenDC);
134 nOK = ReleaseDC(NULL, ScreenDC);
142 * Open a DIB file and return a MEMORY DIB, a memory handle containing..
149 int DibWriteFile(LPTSTR szFile, LPBITMAPINFOHEADER lpbi)
154 fh = OpenFile(wxConvFile.cWX2MB(szFile), &of, OF_WRITE | OF_CREATE);
157 // printf("la regamos0");
161 long size = DibSize(lpbi);
164 BITMAPFILEHEADER bmf;
166 bmf.bfSize = sizeof(bmf) + size;
169 bmf.bfOffBits = sizeof(bmf) + (char FAR*)(DibPtr(lpbi)) - (char FAR*)lpbi;
170 #if defined( __WATCOMC__) || defined(__VISUALC__) || defined(__SC__) || defined(__SALFORDC__) || defined(__MWERKS__) || defined(wxUSE_NORLANDER_HEADERS)
171 if (_hwrite(fh, (LPCSTR)(&bmf), sizeof(bmf))<0 ||
172 _hwrite(fh, (LPCSTR)lpbi, size)<0) {
174 // printf("la regamos1");
178 if (_hwrite(fh, (LPBYTE)(&bmf), sizeof(bmf))<0 ||
179 _hwrite(fh, (LPBYTE)lpbi, size)<0) {
181 // printf("la regamos1");
190 PDIB DibOpenFile(LPTSTR szFile)
199 #if defined(WIN32) || defined(_WIN32)
200 #define GetCurrentInstance() GetModuleHandle(NULL)
202 #define GetCurrentInstance() (HINSTANCE)SELECTOROF((LPVOID)&of)
205 fh = OpenFile(wxConvFile.cWX2MB(szFile), &of, OF_READ);
211 // TODO: Unicode version
213 h = FindResource(GetCurrentInstance(), szFile, RT_BITMAP);
215 h = FindResourceW(GetCurrentInstance(), szFile, RT_BITMAP);
217 h = FindResourceA(GetCurrentInstance(), szFile, RT_BITMAP);
220 #if defined(__WIN32__)
221 //!!! can we call GlobalFree() on this? is it the right format.
222 //!!! can we write to this resource?
224 return (PDIB)LockResource(LoadResource(GetCurrentInstance(), h));
227 fh = AccessResource(GetCurrentInstance(), h);
234 pdib = DibReadBitmapInfo(fh);
239 /* How much memory do we need to hold the DIB */
241 dwBits = pdib->biSizeImage;
242 dwLen = pdib->biSize + DibPaletteSize(pdib) + dwBits;
244 /* Can we get more memory? */
246 p = GlobalReAllocPtr(pdib,dwLen,0);
260 /* read in the bits */
261 _hread(fh, (LPBYTE)pdib + (UINT)pdib->biSize + DibPaletteSize(pdib), dwBits);
271 * ReadDibBitmapInfo()
273 * Will read a file in DIB format and return a global HANDLE to its
274 * BITMAPINFO. This function will work with both "old" and "new"
275 * bitmap formats, but will always return a "new" BITMAPINFO.
278 PDIB DibReadBitmapInfo(HFILE fh)
294 off = _llseek(fh,0L,SEEK_CUR);
296 if (sizeof(bf) != _lread(fh,(LPSTR)&bf,sizeof(bf)))
300 * do we have a RC HEADER?
302 if (bf.bfType != BFT_BITMAP)
305 _llseek(fh,off,SEEK_SET);
308 if (sizeof(bi) != _lread(fh,(LPSTR)&bi,sizeof(bi)))
312 * what type of bitmap info is this?
314 switch (size = (int)bi.biSize)
317 case sizeof(BITMAPINFOHEADER):
320 case sizeof(BITMAPCOREHEADER):
321 bc = *(BITMAPCOREHEADER*)&bi;
322 bi.biSize = sizeof(BITMAPINFOHEADER);
323 bi.biWidth = (DWORD)bc.bcWidth;
324 bi.biHeight = (DWORD)bc.bcHeight;
325 bi.biPlanes = (UINT)bc.bcPlanes;
326 bi.biBitCount = (UINT)bc.bcBitCount;
327 bi.biCompression = BI_RGB;
329 bi.biXPelsPerMeter = 0;
330 bi.biYPelsPerMeter = 0;
332 bi.biClrImportant = 0;
334 _llseek(fh,(LONG)sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER),SEEK_CUR);
339 nNumColors = DibNumColors(&bi);
342 if (bi.biSizeImage == 0)
343 bi.biSizeImage = DibSizeImage(&bi);
345 if (bi.biClrUsed == 0)
346 bi.biClrUsed = DibNumColors(&bi);
351 pdib = (PDIB)GlobalAllocPtr(GMEM_MOVEABLE,(LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
358 pRgb = DibColors(pdib);
362 if (size == sizeof(BITMAPCOREHEADER))
365 * convert a old color table (3 byte entries) to a new
366 * color table (4 byte entries)
368 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBTRIPLE));
370 for (i=nNumColors-1; i>=0; i--)
374 rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
375 rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
376 rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
377 rgb.rgbReserved = (BYTE)0;
384 _lread(fh,(LPVOID)pRgb,nNumColors * sizeof(RGBQUAD));
388 if (bf.bfOffBits != 0L)
389 _llseek(fh,off + bf.bfOffBits,SEEK_SET);
395 * DibSetUsage(hdib,hpal,wUsage)
397 * Modifies the color table of the passed DIB for use with the wUsage
398 * parameter specifed.
400 * if wUsage is DIB_PAL_COLORS the DIB color table is set to 0-256
401 * if wUsage is DIB_RGB_COLORS the DIB color table is set to the RGB values
402 * in the passed palette
405 BOOL DibSetUsage(PDIB pdib, HPALETTE hpal,UINT wUsage)
407 PALETTEENTRY ape[256];
414 hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
419 nColors = DibNumColors(pdib);
421 if (nColors == 3 && DibCompression(pdib) == BI_BITFIELDS)
426 pRgb = DibColors(pdib);
431 // Set the DIB color table to palette indexes
434 for (pw = (WORD FAR*)pRgb,n=0; n<nColors; n++,pw++)
439 // Set the DIB color table to RGBQUADS
443 nColors = (nColors < 256) ? nColors: 256;
445 GetPaletteEntries(hpal,0,nColors,ape);
447 for (n=0; n<nColors; n++)
449 pRgb[n].rgbRed = ape[n].peRed;
450 pRgb[n].rgbGreen = ape[n].peGreen;
451 pRgb[n].rgbBlue = ape[n].peBlue;
452 pRgb[n].rgbReserved = 0;
461 * DibCreate(bits, dx, dy)
463 * Creates a new packed DIB with the given dimensions and the
464 * given number of bits per pixel
467 PDIB DibCreate(int bits, int dx, int dy)
469 LPBITMAPINFOHEADER lpbi ;
474 dwSizeImage = dy*(DWORD)((dx*bits/8+3)&~3);
476 lpbi = (PDIB)GlobalAllocPtr(GHND,sizeof(BITMAPINFOHEADER)+dwSizeImage + 1024);
481 lpbi->biSize = sizeof(BITMAPINFOHEADER) ;
485 lpbi->biBitCount = bits ;
486 lpbi->biCompression = BI_RGB ;
487 lpbi->biSizeImage = dwSizeImage;
488 lpbi->biXPelsPerMeter = 0 ;
489 lpbi->biYPelsPerMeter = 0 ;
490 lpbi->biClrUsed = 0 ;
491 lpbi->biClrImportant = 0 ;
494 lpbi->biClrUsed = 16;
497 lpbi->biClrUsed = 256;
499 pdw = (DWORD FAR *)((LPBYTE)lpbi+(int)lpbi->biSize);
501 for (i=0; i<(int)lpbi->biClrUsed/16; i++)
503 *pdw++ = 0x00000000; // 0000 black
504 *pdw++ = 0x00800000; // 0001 dark red
505 *pdw++ = 0x00008000; // 0010 dark green
506 *pdw++ = 0x00808000; // 0011 mustard
507 *pdw++ = 0x00000080; // 0100 dark blue
508 *pdw++ = 0x00800080; // 0101 purple
509 *pdw++ = 0x00008080; // 0110 dark turquoise
510 *pdw++ = 0x00C0C0C0; // 1000 gray
511 *pdw++ = 0x00808080; // 0111 dark gray
512 *pdw++ = 0x00FF0000; // 1001 red
513 *pdw++ = 0x0000FF00; // 1010 green
514 *pdw++ = 0x00FFFF00; // 1011 yellow
515 *pdw++ = 0x000000FF; // 1100 blue
516 *pdw++ = 0x00FF00FF; // 1101 pink (magenta)
517 *pdw++ = 0x0000FFFF; // 1110 cyan
518 *pdw++ = 0x00FFFFFF; // 1111 white
524 static void xlatClut8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
529 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
531 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
536 static void xlatClut4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
541 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *&)pb)++)
543 for (dw = 0; dw < dwSize; dw++, ((BYTE _huge *)pb)++)
545 *pb = (BYTE)(xlat[*pb & 0x0F] | (xlat[(*pb >> 4) & 0x0F] << 4));
553 static void xlatRle8(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
557 BYTE _huge *prle = pb;
564 if (cnt == RLE_ESCAPE)
583 for (b=0; b<cnt; b++,prle++)
599 static void xlatRle4(BYTE FAR *pb, DWORD dwSize, BYTE FAR *xlat)
603 static void hmemmove(BYTE _huge *d, BYTE _huge *s, LONG len)
613 * DibMapToPalette(pdib, hpal)
615 * Map the colors of the DIB, using GetNearestPaletteIndex, to
616 * the colors of the given palette.
619 BOOL DibMapToPalette(PDIB pdib, HPALETTE hpal)
621 LPBITMAPINFOHEADER lpbi;
634 lpbi = (LPBITMAPINFOHEADER)pdib;
635 lpRgb = DibColors(pdib);
637 GetObject(hpal,sizeof(int),(LPSTR)&nPalColors);
638 nDibColors = DibNumColors(pdib);
640 if ((SizeImage = lpbi->biSizeImage) == 0)
641 SizeImage = DibSizeImage(lpbi);
644 // build a xlat table. from the current DIB colors to the given
647 for (n=0; n<nDibColors; n++)
648 xlat[n] = (BYTE)GetNearestPaletteIndex(hpal,RGB(lpRgb[n].rgbRed,lpRgb[n].rgbGreen,lpRgb[n].rgbBlue));
650 lpBits = (LPBYTE)DibPtr(lpbi);
651 lpbi->biClrUsed = nPalColors;
656 if (nPalColors > nDibColors)
658 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
659 hmemmove((BYTE _huge *)DibPtr(lpbi), (BYTE _huge *)lpBits, SizeImage);
660 lpBits = (LPBYTE)DibPtr(lpbi);
662 else if (nPalColors < nDibColors)
664 hmemcpy(DibPtr(lpbi), lpBits, SizeImage);
665 GlobalReAllocPtr(lpbi, lpbi->biSize + nPalColors*sizeof(RGBQUAD) + SizeImage, 0);
666 lpBits = (LPBYTE)DibPtr(lpbi);
670 // translate the DIB bits
672 switch (lpbi->biCompression)
675 xlatRle8(lpBits, SizeImage, xlat);
679 xlatRle4(lpBits, SizeImage, xlat);
683 if (lpbi->biBitCount == 8)
684 xlatClut8(lpBits, SizeImage, xlat);
686 xlatClut4(lpBits, SizeImage, xlat);
691 // Now copy the RGBs in the logical palette to the dib color table
693 for (n=0; n<nPalColors; n++)
695 GetPaletteEntries(hpal,n,1,&pe);
697 lpRgb[n].rgbRed = pe.peRed;
698 lpRgb[n].rgbGreen = pe.peGreen;
699 lpRgb[n].rgbBlue = pe.peBlue;
700 lpRgb[n].rgbReserved = (BYTE)0;
707 HPALETTE MakePalette(const BITMAPINFO FAR* Info, UINT flags)
710 const RGBQUAD FAR* rgb = Info->bmiColors;
712 WORD nColors = Info->bmiHeader.biClrUsed;
714 LOGPALETTE* logPal = (LOGPALETTE*)
715 new BYTE[sizeof(LOGPALETTE) + (nColors-1)*sizeof(PALETTEENTRY)];
717 logPal->palVersion = 0x300; // Windows 3.0 version
718 logPal->palNumEntries = nColors;
719 for (WORD n = 0; n < nColors; n++) {
720 logPal->palPalEntry[n].peRed = rgb[n].rgbRed;
721 logPal->palPalEntry[n].peGreen = rgb[n].rgbGreen;
722 logPal->palPalEntry[n].peBlue = rgb[n].rgbBlue;
723 logPal->palPalEntry[n].peFlags = (BYTE)flags;
725 hPalette = ::CreatePalette(logPal);