/************************************************************************** * * SETDI.C - contains routines for doing a SetDIBits() into a bitmap. * **************************************************************************/ #include #include #include #include "lockbm.h" #include "setdi.h" /************************************************************************** * * format conversion functions. * * special functions.... * copy_8_8 (no translate) * dither_8_8 (dither from 8bpp to fixed color device (like VGA, SVGA...) * **************************************************************************/ extern CONVERTPROC copy_8_8, dither_8_8; extern CONVERTPROC convert_8_8, convert_8_16, convert_8_24, convert_8_32, convert_8_VGA, convert_8_565, convert_8_RGB, convert_8_RGBX; extern CONVERTPROC convert_16_8, convert_16_16, convert_16_24, convert_16_32, convert_16_VGA, convert_16_565, convert_16_RGB, convert_16_RGBX; extern CONVERTPROC convert_24_8, convert_24_16, convert_24_24, convert_24_32, convert_24_VGA, convert_24_565, convert_24_RGB, convert_24_RGBX; extern CONVERTPROC convert_32_8, convert_32_16, convert_32_24, convert_32_32, convert_32_VGA, convert_32_565, convert_32_RGB, convert_32_RGBX; static INITPROC init_8_8, init_8_16, init_8_24, init_8_32, init_8_VGA, init_8_565, init_8_RGB, init_8_RGBX; static INITPROC init_16_8, init_16_16, init_16_24, init_16_32, init_16_VGA, init_16_565, init_16_RGB, init_16_RGBX; static INITPROC init_24_8, init_24_16, init_24_24, init_24_32, init_24_VGA, init_24_565, init_24_RGB, init_24_RGBX; static INITPROC init_32_8, init_32_16, init_32_24, init_32_32, init_32_VGA, init_32_565, init_32_RGB, init_32_RGBX; static INITPROC init_setdi; static CONVERTPROC convert_setdi; static FREEPROC free_common; static LPVOID init_dither_8_8(HDC hdc, LPBITMAPINFOHEADER lpbi); /************************************************************************** * * some conversions we dont do * **************************************************************************/ #define convert_8_VGA NULL #define convert_16_VGA NULL #define convert_24_VGA NULL #define convert_32_VGA NULL #define convert_8_32 NULL #define convert_16_32 NULL #define convert_24_32 NULL #define convert_32_32 NULL #define convert_8_RGBX NULL #define convert_16_RGBX NULL #define convert_24_RGBX NULL #define convert_32_RGBX NULL #define convert_8_RGB NULL #define convert_16_RGB NULL #define convert_24_RGB NULL #define convert_32_RGB NULL #define convert_16_8 NULL // not now later! #define convert_24_8 NULL #define convert_32_8 NULL /************************************************************************** * * format conversion tables... * * BITMAP types * * 8 0 * 16 1 * 24 2 * 32 3 * VGA 4 * 16 565 5 * 24 RGB 6 * 32 RGB 7 * **************************************************************************/ static PCONVERTPROC ConvertProcTable[4][8] = { {convert_8_8, convert_8_16, convert_8_24, convert_8_32, convert_8_VGA, convert_8_565, convert_8_RGB, convert_8_RGBX}, {convert_16_8, convert_16_16, convert_16_24, convert_16_32, convert_16_VGA, convert_16_565, convert_16_RGB, convert_16_RGBX}, {convert_24_8, convert_24_16, convert_24_24, convert_24_32, convert_24_VGA, convert_24_565, convert_24_RGB, convert_24_RGBX}, {convert_32_8, convert_32_16, convert_32_24, convert_32_32, convert_32_VGA, convert_32_565, convert_32_RGB, convert_32_RGBX}, }; static PINITPROC InitProcTable[4][8] = { {init_8_8, init_8_16, init_8_24, init_8_32, init_8_VGA, init_8_565, init_8_RGB, init_8_RGBX}, {init_16_8, init_16_16, init_16_24, init_16_32, init_16_VGA, init_16_565, init_16_RGB, init_16_RGBX}, {init_24_8, init_24_16, init_24_24, init_24_32, init_24_VGA, init_24_565, init_24_RGB, init_24_RGBX}, {init_32_8, init_32_16, init_32_24, init_32_32, init_32_VGA, init_32_565, init_32_RGB, init_32_RGBX}, }; /************************************************************************** **************************************************************************/ #define RGB555(r,g,b) (\ (((WORD)(r) >> 3) << 10) | \ (((WORD)(g) >> 3) << 5) | \ (((WORD)(b) >> 3) << 0) ) #define RGB565(r,g,b) (\ (((WORD)(r) >> 3) << 11) | \ (((WORD)(g) >> 2) << 5) | \ (((WORD)(b) >> 3) << 0) ) /************************************************************************** **************************************************************************/ #ifdef DEBUG static #else __inline #endif LONG BitmapXY(IBITMAP *pbm, int x, int y) { LONG offset = pbm->bmOffset; //!!! wrong!!! but y for bitmaps is always zero.... // if (pbm->bmFillBytes) // offset += (y / pbm->bmScanSegment) * pbm->bmFillBytes; offset += y * (long)pbm->bmNextScan; offset += x * pbm->bmBitsPixel / 8; return offset; } /************************************************************************** * @doc INTERNAL SetBitmapBegin * * @api BOOL | SetBitmapBegin | prepare to do a SetDIBits() into a bitmap * * @rdesc Returns TRUE if success. * **************************************************************************/ BOOL FAR SetBitmapBegin( PSETDI psd, HDC hdc, // HBITMAP hbm, // bitmap to set into LPBITMAPINFOHEADER lpbi, // --> BITMAPINFO of source UINT DibUsage) { BITMAP bm; SetBitmapEnd(psd); // free and old stuff GetObject(hbm, sizeof(bm), &bm); psd->hbm = hbm; // psd->hdc = hdc; // psd->hpal = hpal; psd->DibUsage= DibUsage; psd->color_convert = NULL; psd->convert = NULL; psd->size = sizeof(SETDI); if (!GetBitmapDIB(lpbi, NULL, &psd->bmSrc, sizeof(psd->bmSrc))) return FALSE; // // make sure we can lock the bitmap // if (GetBitmap(hbm, &psd->bmDst, sizeof(psd->bmDst)) && psd->bmDst.bmFillBytes <= 0 && psd->bmSrc.bmType > 0 && psd->bmSrc.bmType <= 4 && psd->bmDst.bmType > 0 && psd->bmDst.bmType <= 8) { psd->init = InitProcTable[psd->bmSrc.bmType-1][psd->bmDst.bmType-1]; psd->convert = ConvertProcTable[psd->bmSrc.bmType-1][psd->bmDst.bmType-1]; psd->free = free_common; } // // if we cant convert ourself try SetDIBits() // if (psd->convert == NULL) { psd->convert = convert_setdi; psd->init = init_setdi; psd->free = NULL; } if (psd->init) { psd->hdc = hdc; if (!psd->init(psd)) { psd->hdc = 0; psd->size = 0; psd->convert = NULL; return FALSE; } psd->hdc = NULL; psd->hpal = NULL; } return TRUE; } /************************************************************************** * @doc INTERNAL SetBitmapColorChange * * @api BOOL | SetBitmapColorChange | re-init the color conversion * * @rdesc Returns TRUE if success. * **************************************************************************/ void FAR SetBitmapColorChange(PSETDI psd, HDC hdc, HPALETTE hpal) { if (psd->size != sizeof(SETDI)) return; if (hdc == NULL) return; if (psd->free) //!!! ack? psd->free(psd); psd->hdc = hdc; psd->hpal = hpal; if (psd->init) psd->init(psd); psd->hdc = NULL; psd->hpal = NULL; } /************************************************************************** * @doc INTERNAL SetBitmapEnd * * @api void | SetBitmapEnd | clean out a SETDI structure * **************************************************************************/ void FAR SetBitmapEnd(PSETDI psd) { if (psd->size != sizeof(SETDI)) return; if (psd->free) psd->free(psd); psd->size = 0; psd->convert = NULL; psd->init = NULL; psd->free = NULL; } /************************************************************************** * @doc INTERNAL SetBitmap * * @api BOOL | SetBitmap | convert DIB bits to bitmaps bits. * **************************************************************************/ BOOL FAR SetBitmap(PSETDI psd, int DstX, int DstY, int DstDX, int DstDY, LPVOID lpBits, int SrcX, int SrcY, int SrcDX, int SrcDY) { if (psd->size != sizeof(SETDI)) return FALSE; psd->convert( psd->bmDst.bmBits, // --> dst. BitmapXY(&psd->bmDst, DstX, DstY), // offset to start at psd->bmDst.bmNextScan, // dst_next_scan. psd->bmDst.bmFillBytes, // fill bytes lpBits, // --> Src. BitmapXY(&psd->bmSrc, SrcX, SrcY), // offset to start at psd->bmSrc.bmNextScan, // Src_next_scan. DstDX, DstDY, psd->color_convert); return TRUE; } /************************************************************************** * * cleanup stuff * **************************************************************************/ static BOOL free_common(PSETDI psd) { // // clean up what we did // if (psd->color_convert != NULL) GlobalFreePtr(psd->color_convert); psd->color_convert = NULL; return TRUE; } /************************************************************************** * * GetBackgroundTranslate * * get the foreground to background translate table. * * does this by calling GDI, this should always work. * this only works on a palette device. * **************************************************************************/ BOOL GetBackgroundTranslate(HDC hdc, LPBYTE pb) { int i; int n; DWORD rgb; DWORD *prgb; #ifndef _WIN32 // until we can find this on NT... make it 16bit only extern BOOL FAR PASCAL IsDCCurrentPalette(HDC hdc); if (IsDCCurrentPalette(hdc)) { for (i=0; i<256; i++) pb[i] = i; return TRUE; } #endif prgb = (DWORD *)LocalAlloc(LPTR, 256 * sizeof(DWORD)); if (prgb == NULL) return TRUE; GetSystemPaletteEntries(hdc, 0, 256,(PALETTEENTRY FAR *)prgb); for (n=0; n<256; n++) //!!! is this needed. prgb[n] &= 0x00FFFFFF; for (i=0; i<256; i++) { // // GDI will figure out what physical color this palette // index is mapped to. // rgb = GetNearestColor(hdc, PALETTEINDEX(i)) & 0x00FFFFFF; // // quick check for identity map. // if (prgb[i] == rgb) { pb[i] = (BYTE)i; continue; } // // now we have to find the rgb in the physical palette // for (n=0; n<256; n++) if (prgb[n] == rgb) break; // // our search should never fail, because GDI gave us a RGB // in the palette. // if (n == 256) //!!! should never happen n = 0; pb[i] = (BYTE)n; } LocalFree((HLOCAL)prgb); return TRUE; } /************************************************************************** * * @doc INTERNAL GetPaletteMap * * @api BOOL | GetPhysPaletteMap | gets the physical mapping for a DIB * * returns TRUE if the mapping is a 1:1 mapping, FALSE otherwise * **************************************************************************/ BOOL GetPhysDibPaletteMap(HDC hdc, LPBITMAPINFOHEADER lpbi, UINT Usage, LPBYTE pb) { int i; int n; BYTE ab[256]; GetDibPaletteMap(hdc, lpbi, Usage, pb); GetBackgroundTranslate(hdc, ab); // // translate forground palette to physical // for (i=0; i<256; i++) pb[i] = ab[pb[i]]; // // test for 1:1 // n = (int)lpbi->biClrUsed ? (int)lpbi->biClrUsed : 256; for (i=0; ibiWidth; LONG biHeight = lpbi->biHeight; LONG biSizeImage = lpbi->biSizeImage; n = (int)lpbi->biClrUsed ? (int)lpbi->biClrUsed : 256; for (i=0; ibiBitCount != 8) return FALSE; hbm = CreateCompatibleBitmap(hdc,256,1); lpbi->biSizeImage = 256; lpbi->biWidth = 256; lpbi->biHeight = 1; SetDIBits(hdc, hbm, 0, 1, pb, (LPBITMAPINFO)lpbi, Usage); GetBitmapBits(hbm, 256, pb); DeleteObject(hbm); lpbi->biWidth = biWidth; lpbi->biHeight = biHeight; lpbi->biSizeImage = biSizeImage; // // test for 1:1 translate // for (i=0; i dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { PSETDI psd = (PSETDI)(LONG_PTR)pd; LPBITMAPINFOHEADER lpbi; lpbi = (LPBITMAPINFOHEADER)psd->bmSrc.bmBitmapInfo; lpbi->biHeight = dy; SetDIBits( psd->hdc, psd->hbm, 0,(int)dy, ((BYTE _huge *)ps) + ds - dd, (LPBITMAPINFO)lpbi, psd->DibUsage); lpbi->biHeight = psd->bmSrc.bmHeight; } /************************************************************************** * * init stuff for SetDIBits * **************************************************************************/ static BOOL init_setdi(PSETDI psd) { UINT u; HDC hdc; LPBYTE p; LPBITMAPINFOHEADER lpbi; // test to see if SetDIBits() works. // !!! we should check for 16 or a 32bit DIB and do the escape. // !!! on a palette device we need to build a palette map!!! if (psd->bmSrc.bmBitsPixel == 16 || psd->bmSrc.bmBitsPixel == 32) return FALSE; // convert_setdi will need this. psd->bmDst.bmBits = (LPVOID)(UINT_PTR)psd; psd->bmDst.bmOffset = 0; psd->bmDst.bmBitsPixel = psd->bmSrc.bmBitsPixel; if (psd->hdc && psd->hpal) { // map colors to current palette!!!!!!!!!!!!!!!!!!!!!!!!!! //set this to be the BITMAPINFO + color map. psd->color_convert = 0; } lpbi = (LPBITMAPINFOHEADER)psd->bmSrc.bmBitmapInfo; lpbi->biHeight = 1; p = (LPBYTE)GlobalAllocPtr(GHND,psd->bmSrc.bmWidthBytes); hdc = GetDC(NULL); u = SetDIBits( hdc, psd->hbm,0,1,p, (LPBITMAPINFO)psd->bmSrc.bmBitmapInfo, psd->DibUsage); ReleaseDC(NULL, hdc); lpbi->biHeight = psd->bmSrc.bmHeight; GlobalFreePtr(p); return u == 1; } /************************************************************************** * * init stuff for 8bpp bitmaps * **************************************************************************/ static BOOL init_8_8(PSETDI psd) { LPBITMAPINFOHEADER lpbi; // // if we are mapping from one DIB to another figure this out // if (psd->hdc == NULL || psd->bmDst.bmBitmapInfo != 0) { // we assume this routine will not be used for color matching // from DIB to DIB, so give up. psd->convert = copy_8_8; return TRUE; } // // we are mapping to a device (HDC) // // we need to compute a 8-->8 conversion table, from the source colors // (in psd->lpbiSrc) to the colors on the device. // // how we do this depends on weather the device is a palette device or not. // lpbi = (LPBITMAPINFOHEADER)psd->bmSrc.bmBitmapInfo; if (GetDeviceCaps(psd->hdc, RASTERCAPS) & RC_PALETTE) { if (psd->hpal == NULL) { // no palette to match to yet psd->convert = copy_8_8; return TRUE; } if (psd->color_convert == NULL) psd->color_convert = GlobalAllocPtr(GHND, 256); // // we can do this one of two ways, // // we can always convert to the palette foreground mapping, or // // we can convert to the current colors always (using this method // we will need to recompute the xlat table on every palette // change) // // lets convert to the current device colors. (this may cause // problems we will check on later...) // // if (GetPhysDibPaletteMap(psd->hdc, lpbi, psd->DibUsage, psd->color_convert)) if (GetDibPaletteMap(psd->hdc, lpbi, psd->DibUsage, psd->color_convert)) psd->convert = copy_8_8; else psd->convert = convert_8_8; } else { // !!!we should check for solid colors (ie no dither needed) and also // check for 1:1 (no translate) if (psd->color_convert == NULL) //!!! psd->color_convert = init_dither_8_8(psd->hdc, lpbi); psd->convert = dither_8_8; //!!! we need to give the device colors to the caller } return TRUE; } static BOOL init_16_8(PSETDI psd) { return FALSE; // we dont handle dither yet! } static BOOL init_24_8(PSETDI psd) { return FALSE; // we dont handle dither yet! } static BOOL init_32_8(PSETDI psd) { return FALSE; // we dont handle dither yet! } /************************************************************************** * * init stuff for 16bpp bitmaps * **************************************************************************/ static BOOL init_8_16(PSETDI psd) { WORD FAR*pw; int i; int n; LPRGBQUAD prgb; LPBITMAPINFOHEADER lpbi; lpbi = (LPBITMAPINFOHEADER)psd->bmSrc.bmBitmapInfo; if (psd->color_convert == NULL) //!!! psd->color_convert = GlobalAllocPtr(GHND, 256*2); n = (lpbi->biClrUsed == 0) ? 256 : (int)lpbi->biClrUsed; prgb = (LPRGBQUAD)((LPBYTE)lpbi + (int)lpbi->biSize); pw = psd->color_convert; for (i=0; ibmSrc.bmBitmapInfo; if (psd->color_convert == NULL) //!!! psd->color_convert = GlobalAllocPtr(GHND, 256*4); n = (lpbi->biClrUsed == 0) ? 256 : (int)lpbi->biClrUsed; prgb = (LPRGBQUAD)((LPBYTE)lpbi + (int)lpbi->biSize); pd = psd->color_convert; for (i=0; ibmSrc.bmBitmapInfo; if (psd->color_convert == NULL) //!!! psd->color_convert = GlobalAllocPtr(GHND, 256*2); n = (lpbi->biClrUsed == 0) ? 256 : (int)lpbi->biClrUsed; prgb = (LPRGBQUAD)((LPBYTE)lpbi + (int)lpbi->biSize); pw = psd->color_convert; for (i=0; ibmSrc.bmBitmapInfo; if (psd->color_convert == NULL) //!!! psd->color_convert = GlobalAllocPtr(GHND, 256*4); n = (lpbi->biClrUsed == 0) ? 256 : (int)lpbi->biClrUsed; prgb = (LPRGBQUAD)((LPBYTE)lpbi + (int)lpbi->biSize); pd = psd->color_convert; for (i=0; ibiClrUsed) == 0) nColors = 1 << (int)lpbi->biBitCount; prgb = (LPRGBQUAD)(lpbi+1); for (i=0; i dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_16_24 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_16_565 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_24_16 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_24_24 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_24_565 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_32_16 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_32_24 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_32_565 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_8_16 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_8_24 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_8_565 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL convert_8_8 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL copy_8_8 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } void FAR PASCAL dither_8_8 (LPVOID pd, // --> dst. LONG dd, // offset to start at LONG nd, // dst_next_scan. LONG fd, // dst fill bytes LPVOID ps, // --> source. LONG ds, // offset to start at LONG ns, // src_next_scan. LONG dx, // pixel count. LONG dy, // scan count. LPVOID pc) // pixel convert table. { return; } #endif