517 lines
11 KiB
C++
517 lines
11 KiB
C++
|
/*----------------------------------------------------------------------------*\
|
||
|
| Routines for dealing with Device independent bitmaps |
|
||
|
| |
|
||
|
| History: |
|
||
|
| 06/23/89 toddla Created |
|
||
|
| |
|
||
|
\*----------------------------------------------------------------------------*/
|
||
|
|
||
|
#include <windows.h>
|
||
|
#include <stdio.h>
|
||
|
#include "dib.h"
|
||
|
|
||
|
#define HUGE_T
|
||
|
|
||
|
/*
|
||
|
* Open a DIB file and return a MEMORY DIB, a memory handle containing..
|
||
|
*
|
||
|
* BITMAP INFO bi
|
||
|
* palette data
|
||
|
* bits....
|
||
|
*
|
||
|
*/
|
||
|
HANDLE OpenDIB(LPTSTR szFile, HFILE fh)
|
||
|
{
|
||
|
BITMAPINFOHEADER bi;
|
||
|
LPBITMAPINFOHEADER lpbi;
|
||
|
DWORD dwLen;
|
||
|
DWORD dwBits;
|
||
|
HANDLE hdib;
|
||
|
HANDLE h;
|
||
|
#ifndef UNICODE
|
||
|
OFSTRUCT of;
|
||
|
#endif
|
||
|
BOOL fOpened = FALSE;
|
||
|
|
||
|
if (szFile != NULL)
|
||
|
{
|
||
|
#ifdef UNICODE
|
||
|
fh = (HFILE)HandleToUlong(CreateFile(szFile, GENERIC_READ, FILE_SHARE_READ,
|
||
|
NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL));
|
||
|
#else
|
||
|
fh = OpenFile(szFile, &of, OF_READ);
|
||
|
#endif
|
||
|
fOpened = TRUE;
|
||
|
}
|
||
|
|
||
|
if (fh == -1)
|
||
|
return NULL;
|
||
|
|
||
|
hdib = ReadDibBitmapInfo(fh);
|
||
|
|
||
|
if (!hdib)
|
||
|
return NULL;
|
||
|
|
||
|
DibInfo((LPBITMAPINFOHEADER)GlobalLock(hdib),&bi); GlobalUnlock(hdib);
|
||
|
|
||
|
/* How much memory do we need to hold the DIB */
|
||
|
|
||
|
dwBits = bi.biSizeImage;
|
||
|
dwLen = bi.biSize + PaletteSize(&bi) + dwBits;
|
||
|
|
||
|
/* Can we get more memory? */
|
||
|
|
||
|
h = GlobalReAlloc(hdib,dwLen,GMEM_MOVEABLE);
|
||
|
|
||
|
if (!h)
|
||
|
{
|
||
|
GlobalFree(hdib);
|
||
|
hdib = NULL;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
hdib = h;
|
||
|
}
|
||
|
|
||
|
if (hdib)
|
||
|
{
|
||
|
lpbi = (BITMAPINFOHEADER*)GlobalLock(hdib);
|
||
|
|
||
|
/* read in the bits */
|
||
|
_lread(fh, (LPBYTE)lpbi + (UINT)lpbi->biSize + PaletteSize(lpbi), dwBits);
|
||
|
|
||
|
GlobalUnlock(hdib);
|
||
|
}
|
||
|
|
||
|
if (fOpened)
|
||
|
_lclose(fh);
|
||
|
|
||
|
return hdib;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* DibInfo(hbi, lpbi)
|
||
|
*
|
||
|
* retrives the DIB info associated with a CF_DIB format memory block.
|
||
|
*/
|
||
|
BOOL DibInfo(LPBITMAPINFOHEADER lpbiSource, LPBITMAPINFOHEADER lpbiTarget)
|
||
|
{
|
||
|
if (lpbiSource)
|
||
|
{
|
||
|
*lpbiTarget = *lpbiSource;
|
||
|
|
||
|
if (lpbiTarget->biSize == sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
BITMAPCOREHEADER bc;
|
||
|
|
||
|
bc = *(LPBITMAPCOREHEADER)lpbiTarget;
|
||
|
|
||
|
lpbiTarget->biSize = sizeof(BITMAPINFOHEADER);
|
||
|
lpbiTarget->biWidth = (DWORD)bc.bcWidth;
|
||
|
lpbiTarget->biHeight = (DWORD)bc.bcHeight;
|
||
|
lpbiTarget->biPlanes = (UINT)bc.bcPlanes;
|
||
|
lpbiTarget->biBitCount = (UINT)bc.bcBitCount;
|
||
|
lpbiTarget->biCompression = BI_RGB;
|
||
|
lpbiTarget->biSizeImage = 0;
|
||
|
lpbiTarget->biXPelsPerMeter = 0;
|
||
|
lpbiTarget->biYPelsPerMeter = 0;
|
||
|
lpbiTarget->biClrUsed = 0;
|
||
|
lpbiTarget->biClrImportant = 0;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* fill in the default fields
|
||
|
*/
|
||
|
if (lpbiTarget->biSize != sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
if (lpbiTarget->biSizeImage == 0L)
|
||
|
lpbiTarget->biSizeImage = (DWORD)DIBWIDTHBYTES(*lpbiTarget) * lpbiTarget->biHeight;
|
||
|
|
||
|
if (lpbiTarget->biClrUsed == 0L)
|
||
|
lpbiTarget->biClrUsed = DibNumColors(lpbiTarget);
|
||
|
}
|
||
|
return TRUE;
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* ReadDibBitmapInfo()
|
||
|
*
|
||
|
* Will read a file in DIB format and return a global HANDLE to it's
|
||
|
* BITMAPINFO. This function will work with both "old" and "new"
|
||
|
* bitmap formats, but will always return a "new" BITMAPINFO
|
||
|
*
|
||
|
*/
|
||
|
HANDLE ReadDibBitmapInfo(HFILE fh)
|
||
|
{
|
||
|
DWORD off;
|
||
|
HANDLE hbi = NULL;
|
||
|
int size;
|
||
|
int i;
|
||
|
UINT nNumColors;
|
||
|
|
||
|
RGBQUAD FAR *pRgb;
|
||
|
BITMAPINFOHEADER bi;
|
||
|
BITMAPCOREHEADER bc;
|
||
|
LPBITMAPINFOHEADER lpbi;
|
||
|
BITMAPFILEHEADER bf;
|
||
|
|
||
|
if (fh == -1)
|
||
|
return NULL;
|
||
|
|
||
|
off = _llseek(fh,0L,SEEK_CUR);
|
||
|
|
||
|
if (sizeof(bf) != _lread(fh,(LPBYTE)&bf,sizeof(bf)))
|
||
|
return FALSE;
|
||
|
|
||
|
/*
|
||
|
* do we have a RC HEADER?
|
||
|
*/
|
||
|
if (!ISDIB(bf.bfType))
|
||
|
{
|
||
|
bf.bfOffBits = 0L;
|
||
|
_llseek(fh,off,SEEK_SET);
|
||
|
}
|
||
|
|
||
|
if (sizeof(bi) != _lread(fh,(LPBYTE)&bi,sizeof(bi)))
|
||
|
return FALSE;
|
||
|
|
||
|
nNumColors = DibNumColors(&bi);
|
||
|
|
||
|
/*
|
||
|
* what type of bitmap info is this?
|
||
|
*/
|
||
|
switch (size = (int)bi.biSize)
|
||
|
{
|
||
|
case sizeof(BITMAPINFOHEADER):
|
||
|
break;
|
||
|
|
||
|
case sizeof(BITMAPCOREHEADER):
|
||
|
bc = *(BITMAPCOREHEADER*)&bi;
|
||
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bi.biWidth = (DWORD)bc.bcWidth;
|
||
|
bi.biHeight = (DWORD)bc.bcHeight;
|
||
|
bi.biPlanes = (UINT)bc.bcPlanes;
|
||
|
bi.biBitCount = (UINT)bc.bcBitCount;
|
||
|
bi.biCompression = BI_RGB;
|
||
|
bi.biSizeImage = 0;
|
||
|
bi.biXPelsPerMeter = 0;
|
||
|
bi.biYPelsPerMeter = 0;
|
||
|
bi.biClrUsed = nNumColors;
|
||
|
bi.biClrImportant = nNumColors;
|
||
|
|
||
|
_llseek(fh,(LONG)(sizeof(BITMAPCOREHEADER)-sizeof(BITMAPINFOHEADER)),SEEK_CUR);
|
||
|
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
return NULL; /* not a DIB */
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* fill in some default values!
|
||
|
*/
|
||
|
if (bi.biSizeImage == 0)
|
||
|
{
|
||
|
bi.biSizeImage = (DWORD)DIBWIDTHBYTES(bi) * bi.biHeight;
|
||
|
}
|
||
|
|
||
|
if (bi.biXPelsPerMeter == 0)
|
||
|
{
|
||
|
bi.biXPelsPerMeter = 0; // ??????????????
|
||
|
}
|
||
|
|
||
|
if (bi.biYPelsPerMeter == 0)
|
||
|
{
|
||
|
bi.biYPelsPerMeter = 0; // ??????????????
|
||
|
}
|
||
|
|
||
|
if (bi.biClrUsed == 0)
|
||
|
{
|
||
|
bi.biClrUsed = DibNumColors(&bi);
|
||
|
}
|
||
|
|
||
|
hbi = GlobalAlloc(GMEM_MOVEABLE,(LONG)bi.biSize + nNumColors * sizeof(RGBQUAD));
|
||
|
if (!hbi)
|
||
|
return NULL;
|
||
|
|
||
|
lpbi = (BITMAPINFOHEADER *)GlobalLock(hbi);
|
||
|
*lpbi = bi;
|
||
|
|
||
|
pRgb = (RGBQUAD FAR *)((LPBYTE)lpbi + bi.biSize);
|
||
|
|
||
|
if (nNumColors)
|
||
|
{
|
||
|
if (size == (int)sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
/*
|
||
|
* convert a old color table (3 byte entries) to a new
|
||
|
* color table (4 byte entries)
|
||
|
*/
|
||
|
_lread(fh,(LPBYTE)pRgb,nNumColors * sizeof(RGBTRIPLE));
|
||
|
|
||
|
for (i=nNumColors-1; i>=0; i--)
|
||
|
{
|
||
|
RGBQUAD rgb;
|
||
|
|
||
|
rgb.rgbRed = ((RGBTRIPLE FAR *)pRgb)[i].rgbtRed;
|
||
|
rgb.rgbBlue = ((RGBTRIPLE FAR *)pRgb)[i].rgbtBlue;
|
||
|
rgb.rgbGreen = ((RGBTRIPLE FAR *)pRgb)[i].rgbtGreen;
|
||
|
rgb.rgbReserved = (BYTE)0;
|
||
|
|
||
|
pRgb[i] = rgb;
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
_lread(fh,(LPBYTE)pRgb,nNumColors * sizeof(RGBQUAD));
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (bf.bfOffBits != 0L)
|
||
|
_llseek(fh,off + bf.bfOffBits,SEEK_SET);
|
||
|
|
||
|
GlobalUnlock(hbi);
|
||
|
return hbi;
|
||
|
}
|
||
|
|
||
|
/* How big is the palette? if bits per pel not 24
|
||
|
* no of bytes to read is 6 for 1 bit, 48 for 4 bits
|
||
|
* 256*3 for 8 bits and 0 for 24 bits
|
||
|
*/
|
||
|
UINT PaletteSize(VOID FAR * pv)
|
||
|
{
|
||
|
#define lpbi ((LPBITMAPINFOHEADER)pv)
|
||
|
#define lpbc ((LPBITMAPCOREHEADER)pv)
|
||
|
|
||
|
UINT NumColors;
|
||
|
|
||
|
NumColors = DibNumColors(lpbi);
|
||
|
|
||
|
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
|
||
|
return NumColors * sizeof(RGBTRIPLE);
|
||
|
else
|
||
|
return NumColors * sizeof(RGBQUAD);
|
||
|
|
||
|
#undef lpbi
|
||
|
#undef lpbc
|
||
|
}
|
||
|
|
||
|
/* How Many colors does this DIB have?
|
||
|
* this will work on both PM and Windows bitmap info structures.
|
||
|
*/
|
||
|
UINT DibNumColors(VOID FAR * pv)
|
||
|
{
|
||
|
#define lpbi ((LPBITMAPINFOHEADER)pv)
|
||
|
#define lpbc ((LPBITMAPCOREHEADER)pv)
|
||
|
|
||
|
int bits;
|
||
|
|
||
|
/*
|
||
|
* with the new format headers, the size of the palette is in biClrUsed
|
||
|
* else is dependent on bits per pixel
|
||
|
*/
|
||
|
if (lpbi->biSize != sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
if (lpbi->biClrUsed != 0)
|
||
|
return (UINT)lpbi->biClrUsed;
|
||
|
|
||
|
bits = lpbi->biBitCount;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
bits = lpbc->bcBitCount;
|
||
|
}
|
||
|
|
||
|
switch (bits)
|
||
|
{
|
||
|
case 1:
|
||
|
return 2;
|
||
|
case 4:
|
||
|
return 16;
|
||
|
case 8:
|
||
|
return 256;
|
||
|
default:
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
#undef lpbi
|
||
|
#undef lpbc
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* DibFromBitmap()
|
||
|
*
|
||
|
* Will create a global memory block in DIB format that represents the DDB
|
||
|
* passed in
|
||
|
*
|
||
|
*/
|
||
|
HANDLE DibFromBitmap(HBITMAP hbm, DWORD biStyle, WORD biBits, HPALETTE hpal, UINT wUsage)
|
||
|
{
|
||
|
BITMAP bm;
|
||
|
BITMAPINFOHEADER bi;
|
||
|
BITMAPINFOHEADER FAR *lpbi;
|
||
|
DWORD dwLen;
|
||
|
int nColors;
|
||
|
HANDLE hdib;
|
||
|
HANDLE h;
|
||
|
HDC hdc;
|
||
|
|
||
|
if (wUsage == 0)
|
||
|
wUsage = DIB_RGB_COLORS;
|
||
|
|
||
|
if (!hbm)
|
||
|
return NULL;
|
||
|
if (hpal == NULL)
|
||
|
hpal = (HPALETTE)GetStockObject(DEFAULT_PALETTE);
|
||
|
|
||
|
GetObject(hbm,sizeof(bm),(LPBYTE)&bm);
|
||
|
#ifdef WIN32
|
||
|
nColors = 0; // GetObject only stores two bytes
|
||
|
#endif
|
||
|
GetObject(hpal,sizeof(nColors),(LPBYTE)&nColors);
|
||
|
|
||
|
if (biBits == 0)
|
||
|
biBits = bm.bmPlanes * bm.bmBitsPixel;
|
||
|
|
||
|
bi.biSize = sizeof(BITMAPINFOHEADER);
|
||
|
bi.biWidth = bm.bmWidth;
|
||
|
bi.biHeight = bm.bmHeight;
|
||
|
bi.biPlanes = 1;
|
||
|
bi.biBitCount = biBits;
|
||
|
bi.biCompression = biStyle;
|
||
|
bi.biSizeImage = 0;
|
||
|
bi.biXPelsPerMeter = 0;
|
||
|
bi.biYPelsPerMeter = 0;
|
||
|
bi.biClrUsed = 0;
|
||
|
bi.biClrImportant = 0;
|
||
|
|
||
|
dwLen = bi.biSize + PaletteSize(&bi);
|
||
|
|
||
|
hdc = CreateCompatibleDC(NULL);
|
||
|
hpal = SelectPalette(hdc,hpal,TRUE);
|
||
|
RealizePalette(hdc); // why is this needed on a MEMORY DC? GDI bug??
|
||
|
|
||
|
hdib = GlobalAlloc(GMEM_MOVEABLE,dwLen);
|
||
|
|
||
|
if (!hdib)
|
||
|
goto exit;
|
||
|
|
||
|
lpbi = (BITMAPINFOHEADER*)GlobalLock(hdib);
|
||
|
|
||
|
*lpbi = bi;
|
||
|
|
||
|
/*
|
||
|
* call GetDIBits with a NULL lpBits param, so it will calculate the
|
||
|
* biSizeImage field for us
|
||
|
*/
|
||
|
GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight,
|
||
|
NULL, (LPBITMAPINFO)lpbi, wUsage);
|
||
|
|
||
|
bi = *lpbi;
|
||
|
GlobalUnlock(hdib);
|
||
|
|
||
|
/*
|
||
|
* HACK! if the driver did not fill in the biSizeImage field, make one up
|
||
|
*/
|
||
|
if (bi.biSizeImage == 0)
|
||
|
{
|
||
|
bi.biSizeImage = (DWORD)WIDTHBYTES(bm.bmWidth * biBits) * bm.bmHeight;
|
||
|
|
||
|
if (biStyle != BI_RGB)
|
||
|
bi.biSizeImage = (bi.biSizeImage * 3) / 2;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* realloc the buffer big enough to hold all the bits
|
||
|
*/
|
||
|
dwLen = bi.biSize + PaletteSize(&bi) + bi.biSizeImage;
|
||
|
if (h = GlobalReAlloc(hdib,dwLen,GMEM_MOVEABLE))
|
||
|
{
|
||
|
hdib = h;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
GlobalFree(hdib);
|
||
|
hdib = NULL;
|
||
|
goto exit;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* call GetDIBits with a NON-NULL lpBits param, and actualy get the
|
||
|
* bits this time
|
||
|
*/
|
||
|
lpbi = (BITMAPINFOHEADER*)GlobalLock(hdib);
|
||
|
|
||
|
GetDIBits(hdc, hbm, 0, (UINT)bi.biHeight,
|
||
|
(LPBYTE)lpbi + (UINT)lpbi->biSize + PaletteSize(lpbi),
|
||
|
(LPBITMAPINFO)lpbi, wUsage);
|
||
|
|
||
|
bi = *lpbi;
|
||
|
lpbi->biClrUsed = DibNumColors(lpbi) ;
|
||
|
GlobalUnlock(hdib);
|
||
|
|
||
|
exit:
|
||
|
SelectPalette(hdc,hpal,TRUE);
|
||
|
DeleteDC(hdc);
|
||
|
return hdib;
|
||
|
}
|
||
|
|
||
|
|
||
|
/*
|
||
|
* DibBlt()
|
||
|
*
|
||
|
* draws a bitmap in CF_DIB format, using SetDIBits to device.
|
||
|
*
|
||
|
* takes the same parameters as BitBlt()
|
||
|
*/
|
||
|
BOOL DibBlt(HDC hdc, int x0, int y0, int dx, int dy, HANDLE hdib, int x1, int y1, LONG rop, UINT wUsage)
|
||
|
{
|
||
|
LPBITMAPINFOHEADER lpbi;
|
||
|
LPBYTE pBuf;
|
||
|
BOOL f;
|
||
|
|
||
|
if (!hdib)
|
||
|
return PatBlt(hdc,x0,y0,dx,dy,rop);
|
||
|
|
||
|
if (wUsage == 0)
|
||
|
wUsage = DIB_RGB_COLORS;
|
||
|
|
||
|
lpbi = (BITMAPINFOHEADER*)GlobalLock(hdib);
|
||
|
|
||
|
if (!lpbi)
|
||
|
return FALSE;
|
||
|
|
||
|
if (dx == -1 && dy == -1)
|
||
|
{
|
||
|
if (lpbi->biSize == sizeof(BITMAPCOREHEADER))
|
||
|
{
|
||
|
dx = ((LPBITMAPCOREHEADER)lpbi)->bcWidth;
|
||
|
dy = ((LPBITMAPCOREHEADER)lpbi)->bcHeight;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dx = (int)lpbi->biWidth;
|
||
|
dy = (int)lpbi->biHeight;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pBuf = (LPBYTE)lpbi + (UINT)lpbi->biSize + PaletteSize(lpbi);
|
||
|
|
||
|
|
||
|
f = StretchDIBits (
|
||
|
hdc,
|
||
|
x0,y0,
|
||
|
dx,dy,
|
||
|
x1,y1,
|
||
|
dx,dy,
|
||
|
pBuf, (LPBITMAPINFO)lpbi,
|
||
|
wUsage,
|
||
|
rop);
|
||
|
|
||
|
GlobalUnlock(hdib);
|
||
|
return f;
|
||
|
}
|
||
|
|