void CImgBitsDIB::SetTransIndex(LONG lIndex) { Assert(_iBitCount <= 8); Assert(lIndex>=-1 && lIndex<(1<<_iBitCount)); _iTrans = lIndex; if(lIndex >= 0) { if(_hbmImg) { HDC hdcMem; HBITMAP hbmSav; hdcMem = GetMemoryDC(); if(!hdcMem) { return; } hbmSav = (HBITMAP)SelectObject(hdcMem, _hbmImg); SetDIBColorTable(hdcMem, lIndex, 1, &g_rgbWhite); SelectObject(hdcMem, hbmSav); ReleaseMemoryDC(hdcMem); } else if(_pbmih) { ((RGBQUAD*)(_pbmih+1))[_iTrans] = g_rgbWhite; } } }
HRESULT CImgBitsDIB::AllocDIBSectionFromInfo(BITMAPINFO* pbmi, BOOL fPal) { HDC hdcMem = NULL; HRESULT hr = S_OK; Assert(!_pvImgBits); Assert(!_hbmImg); _xWidth = pbmi->bmiHeader.biWidth; _yHeight = pbmi->bmiHeader.biHeight; _iBitCount = pbmi->bmiHeader.biBitCount; _yHeightValid = _yHeight; _iTrans = -1; _cColors = pbmi->bmiHeader.biClrUsed; if(_iBitCount==16 && (pbmi->bmiHeader.biCompression!=BI_BITFIELDS || ((DWORD*)(pbmi->bmiColors))[0]!=MASK565_0 || ((DWORD*)(pbmi->bmiColors))[1]!=MASK565_1 || ((DWORD*)(pbmi->bmiColors))[2]!=MASK565_2)) { _iBitCount = 15; } Assert(_iBitCount==1 || _iBitCount==4 || _iBitCount==8 || _iBitCount==15 || _iBitCount==16 || _iBitCount==24 || _iBitCount==32); Assert(_xWidth>0 && _yHeight>0); hdcMem = GetMemoryDC(); if(hdcMem == NULL) { goto OutOfMemory; } _hbmImg = CreateDIBSection(hdcMem, pbmi, fPal?DIB_PAL_COLORS:DIB_RGB_COLORS, &_pvImgBits, NULL, 0); if(!_hbmImg || !_pvImgBits) { goto OutOfMemory; } Cleanup: if(hdcMem) { ReleaseMemoryDC(hdcMem); } RRETURN(hr); OutOfMemory: hr = E_OUTOFMEMORY; goto Cleanup; }
HDC CDIB::GetMemoryDC(HDC hDC /*=NULL*/, BOOL bSelectPalette /*=TRUE*/) { #ifdef DIBSECTION_NO_MEMDC_REUSE ReleaseMemoryDC(TRUE); #else if (!m_bReuseMemDC) { ReleaseMemoryDC(TRUE); } else if (m_hMemDC) // Already created? { return m_hMemDC; } #endif // DIBSECTION_NO_MEMDC_REUSE // Create a memory DC compatible with the given DC m_hMemDC = CreateCompatibleDC(hDC); if (!m_hMemDC) return NULL; // Select in the bitmap m_hOldBitmap = (HBITMAP) ::SelectObject(m_hMemDC, m_hBitmap); // Select in the palette if (bSelectPalette && UsesPalette(m_hMemDC)) { // Palette should already have been created - but just in case... if (!m_hPal) CreatePalette(); m_hOldPal = SelectPalette( m_hMemDC, m_hPal, FALSE ); RealizePalette( m_hMemDC ); } else m_hOldPal = NULL; return m_hMemDC; }
HRESULT CImgBitsDIB::AllocMaskSection() { HRESULT hr = S_OK; HDC hdcMem; struct { BITMAPINFOHEADER bmih; union { RGBQUAD argb[2]; } u; } bmi; memset(&bmi, 0, sizeof(bmi)); bmi.bmih.biSize = sizeof(BITMAPINFOHEADER); bmi.bmih.biWidth = _xWidth; bmi.bmih.biHeight = _yHeight; bmi.bmih.biPlanes = 1; bmi.bmih.biBitCount = 1; bmi.u.argb[1] = g_rgbWhite; hdcMem = GetMemoryDC(); if(hdcMem == NULL) { goto OutOfMemory; } _hbmMask = CreateDIBSection(hdcMem, (BITMAPINFO*)&bmi, DIB_RGB_COLORS, &_pvMaskBits, NULL, 0); if(!_hbmMask || !_pvMaskBits) { goto OutOfMemory; } Cleanup: if(hdcMem) { ReleaseMemoryDC(hdcMem); } RRETURN(hr); OutOfMemory: hr = E_OUTOFMEMORY; goto Cleanup; }
CDIB::~CDIB() { // Unselect the bitmap out of the memory DC before deleting bitmap ReleaseMemoryDC(TRUE); if (m_hBitmap) ::DeleteObject(m_hBitmap); m_hBitmap = NULL; m_ppvBits = NULL; #ifndef DIBSECTION_NO_PALETTE DeleteObject((HGDIOBJ) m_hPal); #endif memset(&m_DIBinfo, 0, sizeof(m_DIBinfo)); m_iColorDataType = DIB_RGB_COLORS; m_iColorTableSize = 0; }
BOOL CDIB::Stretch(HDC hDC, POINT& ptDest, SIZE& size, BOOL bForceBackground /*=FALSE*/) { if (!m_hBitmap) return FALSE; BOOL bResult = FALSE; POINT ptOrigin = {0,0}; SIZE imagesize; GetSize(imagesize); #ifndef _WIN32_WCE //pDC->SetStretchBltMode(COLORONCOLOR); #endif // Create a memory DC compatible with the destination DC HDC hMemDC = GetMemoryDC(hDC, FALSE); if (!hMemDC) return FALSE; #ifndef DIBSECTION_NO_PALETTE // Select and realize the palette HPALETTE hOldPalette = NULL; if (m_hPal && UsesPalette(hDC)) { hOldPalette = SelectPalette(hDC, m_hPal, bForceBackground); RealizePalette(hDC); } #endif // DIBSECTION_NO_PALETTE bResult = StretchBlt(hDC, ptDest.x, ptDest.y, size.cx, size.cy, hMemDC, ptOrigin.x, ptOrigin.y, imagesize.cx, imagesize.cy, SRCCOPY); #ifndef DIBSECTION_NO_PALETTE if (hOldPalette) SelectPalette(hDC, hOldPalette, FALSE); #endif // DIBSECTION_NO_PALETTE ReleaseMemoryDC(); return bResult; }
void CImgBitsDIB::GetColors(long iFirst, long cColors, RGBQUAD* prgb) { if(_hbmImg) { HDC hdcMem; HBITMAP hbmSav; hdcMem = GetMemoryDC(); hbmSav = (HBITMAP)SelectObject(hdcMem, _hbmImg); GetDIBColorTable(hdcMem, iFirst, cColors, prgb); SelectObject(hdcMem, hbmSav); ReleaseMemoryDC(hdcMem); } else { if(iFirst < 0) { memset(prgb, 0, sizeof(RGBQUAD)*-iFirst); prgb -= iFirst; cColors += iFirst; iFirst = 0; } if(iFirst+cColors > _cColors) { memset(prgb+_cColors, 0, sizeof(RGBQUAD)*(iFirst+cColors-_cColors)); cColors = _cColors - iFirst; } if(_fPalColors) { memcpy(prgb, g_rgbHalftone+iFirst, sizeof(RGBQUAD)*cColors); } else { memcpy(prgb, (RGBQUAD*)(_pbmih+1)+iFirst, sizeof(RGBQUAD)*cColors); } } }
BOOL CDIB::Draw(HDC hDC, POINT& ptDest, BOOL bForceBackground /*=FALSE*/) { if (!m_hBitmap) return FALSE; SIZE size; // = GetSize(); POINT ptOrigin = {0,0}; BOOL bResult = FALSE; // Create a memory DC compatible with the destination DC HDC hMemDC = GetMemoryDC(hDC, FALSE); if (!hMemDC) return FALSE; #ifndef DIBSECTION_NO_PALETTE // Select and realize the palette HPALETTE hOldPalette = NULL; if (m_hPal && UsesPalette(hDC)) { hOldPalette = SelectPalette(hDC, m_hPal, bForceBackground ); RealizePalette(hDC); } #endif // DIBSECTION_NO_PALETTE bResult = BitBlt(hDC, ptDest.x, ptDest.y, size.cx, size.cy, hMemDC, ptOrigin.x, ptOrigin.y, SRCCOPY); #ifndef DIBSECTION_NO_PALETTE if (hOldPalette) SelectPalette(hDC, hOldPalette, FALSE); #endif // DIBSECTION_NO_PALETTE ReleaseMemoryDC(); return bResult; }
void CImgBitsDIB::Optimize() { RGBQUAD rgbSolid; if(_iTrans>=0 && !_pvMaskBits) { if(!!ComputeTransMask(0, _yHeightValid, _iTrans, _iTrans)) { return; } } if(!_pvMaskBits) { // If we still don't have a mask, it means there were no transparent bits, so dump _iTrans _iTrans = -1; // check 8-bit images to see if they're solid if(_iBitCount==8 && _pvImgBits) { DWORD dwTest; DWORD* pdw; int cdw; int cLines; dwTest = *(BYTE*)_pvImgBits; dwTest = dwTest | dwTest << 8; dwTest = dwTest | dwTest << 16; pdw = (DWORD*)_pvImgBits; for(cLines=_yHeight; cLines; cLines-=1) { cdw = CbLine() / 4; for(;;) { if(cdw == 1) { // Assumes little endian; shift in other direction for big endian if((dwTest^*pdw) << (8*(3-(0x3&(_xWidth-1))))) { goto NotSolid; } pdw += 1; break; } else if(*pdw != dwTest) { goto NotSolid; } cdw -= 1; pdw += 1; } } // It's solid! So extract the color dwTest &= 0xFF; if(_pbmih) { rgbSolid = ((RGBQUAD*)(_pbmih+1))[dwTest]; } else if(_fPalColors) { rgbSolid = g_rgbHalftone[dwTest]; } else if(_hbmImg) { HDC hdcMem; HBITMAP hbmSav; hdcMem = GetMemoryDC(); if(!hdcMem) { goto NotSolid; } hbmSav = (HBITMAP) SelectObject(hdcMem, _hbmImg); GetDIBColorTable(hdcMem, dwTest, 1, &rgbSolid); SelectObject(hdcMem, hbmSav); ReleaseMemoryDC(hdcMem); } else { goto NotSolid; } // And set up the data _fSolid = TRUE; _crSolid = (rgbSolid.rgbRed) | (rgbSolid.rgbGreen<<8) | (rgbSolid.rgbBlue<<16); FreeMemory(); } } else { // If we have a mask, check to see if the entire image is transparent; if so, dump the data int cdw; int cLines; DWORD* pdw; DWORD dwLast; BYTE bLast; Assert(!(CbLineMask() & 0x3)); bLast = (0xFF << (7-(0x7&(_xWidth-1)))); // Assumes little endian; shift in other direction for big endian dwLast = (unsigned)(0x00FFFFFF | (bLast<<24))>>(8*(3-(0x3&(((7+_xWidth)>>3)-1)))); pdw = (DWORD*)_pvMaskBits; for(cLines=_yHeight; cLines; cLines-=1) { cdw = CbLineMask() / 4; for(;;) { if(cdw == 1) { // Assumes little endian; shift in other direction for big endian if(*pdw & dwLast) { goto NotAllTransparent; } pdw += 1; break; } else if(*pdw) { goto NotAllTransparent; } cdw -= 1; pdw += 1; } } FreeMemory(); return; } NotSolid: NotAllTransparent: ; }
// Draw the src rect of the specified image into the dest rect of the hdc void CImgBitsDIB::StretchBlt(HDC hdc, RECT* prcDst, RECT* prcSrc, DWORD dwRop, DWORD dwFlags) { HDC hdcDib = NULL; HBITMAP hbmSav = NULL; int xDst = prcDst->left; int yDst = prcDst->top; int xDstWid = prcDst->right - xDst; int yDstHei = prcDst->bottom - yDst; int xSrc = prcSrc->left; int ySrc = prcSrc->top; int xSrcWid = prcSrc->right - xSrc; int ySrcHei = prcSrc->bottom - ySrc; int yUseHei = _yHeight; // Cases in which there is nothing to draw if((!_pvImgBits && !_pvMaskBits && !_fSolid) || _yHeightValid==0) { return; } if(xDstWid<=0 || xSrcWid<=0 || _xWidth<=0 || yDstHei<=0 || ySrcHei<=0 || _yHeight<=0) { return; } if(dwRop!=SRCCOPY && (_pvMaskBits || _iTrans>=0)) { return; } // Step 1: Limit the source and dest rectangles to the visible area only. if(_yHeightValid>0 && _yHeightValid<_yHeight) { yUseHei = _yHeightValid; } if(xSrc < 0) { xDst += MulDivQuick(-xSrc, xDstWid, xSrcWid); xDstWid = prcDst->right - xDst; xSrcWid += xSrc; xSrc = 0; if(xDstWid<=0 || xSrcWid<=0) { return; } } if(ySrc < 0) { yDst += MulDivQuick(-ySrc, yDstHei, ySrcHei); yDstHei = prcDst->bottom - yDst; ySrcHei += ySrc; ySrc = 0; if(yDstHei<=0 || ySrcHei<=0) { return; } } if(xSrc+xSrcWid > _xWidth) { xDstWid = MulDivQuick(xDstWid, _xWidth-xSrc, xSrcWid); xSrcWid = _xWidth - xSrc; if(xDstWid<=0 || xSrcWid<=0) { return; } } if(ySrc+ySrcHei > yUseHei) { yDstHei = MulDivQuick(yDstHei, yUseHei-ySrc, ySrcHei); ySrcHei = yUseHei - ySrc; if(yDstHei<=0 || ySrcHei<=0) { return; } } // For the mirrored case, we need flip then offset. if(_fNeedMirroring) { // We need to handle clipping correctly and give a right-to-left tiling effect. // Let's take the "opposite" slice of the source. // The maximum will be the whole image. xSrc = - xSrc +_xWidth - xSrcWid; xDst += xDstWid - 1; xDstWid = - xDstWid; } // Optimization: if solid, just patblt the color if(_fSolid) { // Turn on the palette relative bit for palettized devices in order to ensure that dithering // doesn't happen here. The main reason is that is looks ugly, but more importantly we aren't // prepared to seam multiple copies of the image so that the dithering looks smooth. PatBltBrush(hdc, xDst, yDst, xDstWid, yDstHei, PATCOPY, _crSolid|g_crPaletteRelative); return; } SetStretchBltMode(hdc, COLORONCOLOR); // Step 2: For tranparent images, use mask to whiten drawing area if(_pvMaskBits || _iTrans>=0) { if(dwFlags & DRAWIMAGE_NOTRANS) { goto NoTransparency; } if(GetDeviceCaps(hdc, TECHNOLOGY) == DT_RASPRINTER) { // No transparency for printers that we know lie about their support for transparency. int iEscapeFunction = POSTSCRIPT_PASSTHROUGH; THREADSTATE* pts = GetThreadState(); if(Escape(hdc, QUERYESCSUPPORT, sizeof(int), (LPCSTR)&iEscapeFunction, NULL)) { // Skip transparency unless we are a mask-only image if(_pvImgBits || !_pvMaskBits) { goto NoTransparency; } } } if(_pvMaskBits) { // 1-bit mask case if(_hbmMask) { // We have an HBITMAP, not just bits Assert(!hdcDib && !hbmSav); hdcDib = GetMemoryDC(); if(!hdcDib) { goto Cleanup; } // Special case: use MaskBlt for the whole thing on NT if(xSrcWid==xDstWid && ySrcHei==yDstHei && _hbmImg) { hbmSav = (HBITMAP)SelectObject(hdcDib, _hbmImg); MaskBlt(hdc, xDst, yDst, xDstWid, yDstHei, hdcDib, xSrc, ySrc, _hbmMask, xSrc, ySrc, 0xAACC0020); goto Cleanup; } hbmSav = (HBITMAP)SelectObject(hdcDib, _hbmMask); if(!_pvImgBits) { // a mask-only one-bit image: just draw the "1" bits as black ::StretchBlt(hdc, xDst, yDst, xDstWid, yDstHei, hdcDib, xSrc, ySrc, xSrcWid, ySrcHei, MERGEPAINT); } else { // transparent mask: draw the "1" bits as white ::StretchBlt(hdc, xDst, yDst, xDstWid, yDstHei, hdcDib, xSrc, ySrc, xSrcWid, ySrcHei, SRCPAINT); } } else { // We have just bits, not an HBITMAP struct { BITMAPINFOHEADER bmih; union { RGBQUAD rgb[2]; WORD windex[2]; }; } bmiMask; // construct mask header memset(&bmiMask, 0, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*2); bmiMask.bmih.biSize = sizeof(BITMAPINFOHEADER); bmiMask.bmih.biWidth = _xWidth; bmiMask.bmih.biHeight = _yHeight; bmiMask.bmih.biPlanes = 1; bmiMask.bmih.biBitCount = 1; if(!_pvImgBits) { // a mask-only one-bit image: just draw the "1" bits as black bmiMask.rgb[0] = g_rgbWhite; StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvMaskBits, (BITMAPINFO*)&bmiMask, DIB_RGB_COLORS, SRCAND); } else if(_iBitCount<=8 && _fPalColors && !(dwFlags&DRAWIMAGE_NHPALETTE)) { // this setup only occurs on an 8-bit palettized display; we can use DIB_PAL_COLORS bmiMask.windex[1] = 255; StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvMaskBits, (BITMAPINFO*)&bmiMask, DIB_PAL_COLORS, SRCPAINT); } else { bmiMask.rgb[1] = g_rgbWhite; StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvMaskBits, (BITMAPINFO *)&bmiMask, DIB_RGB_COLORS, SRCPAINT); } } } else { // 1- 4- or 8-bit mask case (with _iTrans) long cTable = 1 << _iBitCount; Assert(_iTrans >= 0); Assert(_iTrans < cTable); Assert(_iBitCount <= 8); if(_hbmImg) { // We have an HBITMAP, not just bits RGBQUAD argbOld[256]; RGBQUAD argbNew[256]; memset(argbNew, 0, sizeof(RGBQUAD)*cTable); argbNew[_iTrans] = g_rgbWhite; Assert(!hdcDib && !hbmSav); hdcDib = GetMemoryDC(); if(!hdcDib) { goto Cleanup; } hbmSav = (HBITMAP)SelectObject(hdcDib, _hbmImg); // HBM case: we need to change the color table, which can only be done one-at-a time g_csImgTransBlt.Enter(); Verify(GetDIBColorTable(hdcDib, 0, cTable, argbOld) > 0); Verify(SetDIBColorTable(hdcDib, 0, cTable, argbNew) == (unsigned)cTable); ::StretchBlt(hdc, xDst, yDst, xDstWid, yDstHei, hdcDib, xSrc, ySrc, xSrcWid, ySrcHei, MERGEPAINT); Verify(SetDIBColorTable(hdcDib, 0, cTable, argbOld) == (unsigned)cTable); g_csImgTransBlt.Leave(); } else { // We have just bits, not an HBITMAP struct { BITMAPINFOHEADER bmih; RGBQUAD rgb[256]; } bmiMask; // construct mask header memset(&bmiMask, 0, sizeof(BITMAPINFOHEADER)+(sizeof(RGBQUAD)*cTable)); bmiMask.bmih.biSize = sizeof(BITMAPINFOHEADER); bmiMask.bmih.biWidth = _xWidth; bmiMask.bmih.biHeight = _yHeight; bmiMask.bmih.biPlanes = 1; bmiMask.bmih.biBitCount = _iBitCount; bmiMask.rgb[_iTrans] = g_rgbWhite; StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvImgBits, (BITMAPINFO*)&bmiMask, DIB_RGB_COLORS, MERGEPAINT); } } // prepare for transparent blt: area to be painted is now whitened, so AND-blt on top of it dwRop = SRCAND; } NoTransparency: // Step 3: Draw the image bits if(_pvImgBits) { if(dwFlags & DRAWIMAGE_MASKONLY) { goto Cleanup; } if(_hbmImg) { // The normal case (not to a Win95 printer): call StretchBlt if(!hdcDib) { hdcDib = GetMemoryDC(); if(!hdcDib) { goto Cleanup; } } HBITMAP hbmOld; hbmOld = (HBITMAP)SelectObject(hdcDib, _hbmImg); if(!hbmSav) { hbmSav = hbmOld; } ::StretchBlt(hdc, xDst, yDst, xDstWid, yDstHei, hdcDib, xSrc, ySrc, xSrcWid, ySrcHei, dwRop); } else { // We have just bits, not an HBITMAP if(!_pbmih) { // No color table header: cobble up a standard header [perhaps these should just be globally cached?] struct { BITMAPINFOHEADER bmih; union { WORD windex[256]; RGBQUAD rgb[256]; DWORD bfmask[3]; }; } bmi; DWORD dwDibMode = DIB_RGB_COLORS; // construct mask header memset(&bmi, 0, sizeof(BITMAPINFOHEADER)+(_iBitCount>8?sizeof(DWORD)*3:sizeof(WORD)*(_iBitCount<<1))); bmi.bmih.biSize = sizeof(BITMAPINFOHEADER); bmi.bmih.biWidth = _xWidth; bmi.bmih.biHeight = _yHeight; bmi.bmih.biPlanes = 1; bmi.bmih.biBitCount = _iBitCount + (_iBitCount==15); if(_iBitCount == 4) { // Thanks to Steve Palmer: fix VGA color rendering bmi.bmih.biClrUsed = 16; bmi.bmih.biClrImportant = 16; CopyColorsFromPaletteEntries(bmi.rgb, g_peVga, 16); } else if(_iBitCount <= 8) { if(dwFlags & DRAWIMAGE_NHPALETTE) { // If being drawn on an <= 8-bit surface from a filter, we can make no assumptions about // the selected palette, so use RGB_COLORS LONG c; c = (1 << (_iBitCount-1)); memcpy(bmi.rgb, g_rgbHalftone, c*sizeof(RGBQUAD)); memcpy(bmi.rgb+c, g_rgbHalftone+256-c, c*sizeof(RGBQUAD)); } else { // internal draw, no color table with _iBitCount <= 8 means that the palette selected into hdc // is our standard 8-bit halftone palette and we can use DIB_PAL_COLORS LONG c; LONG d; WORD* pwi; dwDibMode = DIB_PAL_COLORS; for(c=(1<<(_iBitCount-1)),pwi=bmi.windex+c; c; *(--pwi)=(--c)); for(c=(1<<(_iBitCount-1)),pwi=bmi.windex+c*2,d=256; c; --c,*(--pwi)=(--d)); } } else if(_iBitCount == 16) { // sixteen-bit case: fill in the bitfields mask for 565 bmi.bmih.biCompression = BI_BITFIELDS; bmi.bfmask[0] = MASK565_0; bmi.bfmask[1] = MASK565_1; bmi.bfmask[2] = MASK565_2; } StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvImgBits, (BITMAPINFO*)&bmi, dwDibMode, dwRop); } else { StretchDIBits(hdc, xDst, yDst, xDstWid, yDstHei, xSrc, _yHeight-ySrc-ySrcHei, xSrcWid, ySrcHei, _pvImgBits, (BITMAPINFO*)_pbmih, DIB_RGB_COLORS, dwRop); } } } Cleanup: if(hbmSav) { SelectObject(hdcDib, hbmSav); } if(hdcDib) { ReleaseMemoryDC(hdcDib); } }
HRESULT CImgBitsDIB::AllocCopyBitmap(HBITMAP hbm, BOOL fPalColors, LONG lTrans) { HRESULT hr; LONG iBitCount; struct { BITMAPINFOHEADER bmih; union { RGBQUAD rgb[256]; WORD windex[256]; DWORD dwbc[3]; }; } header; HDC hdc; hdc = GetMemoryDC(); if(!hdc) { return E_OUTOFMEMORY; } memset(&header, 0, sizeof(BITMAPINFOHEADER)+sizeof(RGBQUAD)*256); header.bmih.biSize = sizeof(BITMAPINFOHEADER); GetDIBits(hdc, hbm, 0, 0, NULL, (BITMAPINFO*)&header, fPalColors?DIB_PAL_COLORS:DIB_RGB_COLORS); // A second call to GetDIBits should get the color table if any, but it doesn't work on Win95, so we use // GetDIBColorTable instead (dbau) if(header.bmih.biBitCount <= 8) { HBITMAP hbmSav; hbmSav = (HBITMAP)SelectObject(hdc, hbm); GetDIBColorTable(hdc, 0, 1<<header.bmih.biBitCount, header.rgb); SelectObject(hdc, hbmSav); } iBitCount = header.bmih.biBitCount; if(iBitCount == 16) { if(header.bmih.biCompression!=BI_BITFIELDS || header.dwbc[0]!=MASK565_0 || header.dwbc[1]!=MASK565_1 || header.dwbc[2]!=MASK565_2) { iBitCount = 15; } } BOOL fColorTable = (!fPalColors && iBitCount<=8); if(fColorTable) { hr = AllocDIB(iBitCount, header.bmih.biWidth, header.bmih.biHeight, header.rgb, 1<<iBitCount, lTrans, lTrans==-1); } else { hr = AllocDIB(iBitCount, header.bmih.biWidth, header.bmih.biHeight, NULL, 0, -1, TRUE); } GetDIBits(hdc, hbm, 0, header.bmih.biHeight, GetBits(), (BITMAPINFO*)&header, fPalColors?DIB_PAL_COLORS:DIB_RGB_COLORS); ReleaseMemoryDC(hdc); return S_OK; }
HRESULT CImgBitsDIB::SaveAsBmp(IStream* pStm, BOOL fFileHeader) { HRESULT hr = S_OK; HBITMAP hbmSavDst = NULL; HDC hdcDibDst = NULL; int adjustedwidth; DIBSECTION ds; DWORD dw; int nColors; DWORD dwColors; DWORD dwImage; int cBitsPerPix; CImgBitsDIB* pibd = NULL; HBITMAP hbm; // 1. Get a DIBSECTION structure even if it means allocating another CImgBitsDIB hbm = _hbmImg; if(!hbm || !GetObject(_hbmImg, sizeof(DIBSECTION), &ds)) { RECT rc; int iBitCount; RGBQUAD* prgb; int nColors; // Otherwise, duplicate what we have. iBitCount = _iBitCount; if(_pbmih && iBitCount<=8) { prgb = (RGBQUAD*)(_pbmih + 1); nColors = _pbmih->biClrUsed ? _pbmih->biClrUsed : (1<<iBitCount); } else if(iBitCount == 8) { prgb = g_rgbHalftone; nColors = 256; } else { prgb = NULL; nColors = 0; } pibd = new CImgBitsDIB(); if(!pibd) { goto OutOfMemory; } hr = pibd->AllocDIBSection(iBitCount, _xWidth, _yHeight, prgb, nColors, _iTrans); if(hr) { goto Cleanup; } hbm = pibd->GetHbm(); Assert(hbm); hdcDibDst = GetMemoryDC(); if(!hdcDibDst) { goto OutOfMemory; } rc.left = 0; rc.top = 0; rc.right = _xWidth; rc.bottom = _yHeight; hbmSavDst = (HBITMAP)SelectObject(hdcDibDst, hbm); StretchBlt(hdcDibDst, &rc, &rc, SRCCOPY, DRAWIMAGE_NHPALETTE|DRAWIMAGE_NOTRANS); if(!GetObject(hbm, sizeof(DIBSECTION), &ds)) { goto OutOfMemory; } } // 2. Save it out cBitsPerPix = ds.dsBmih.biBitCount; Assert(cBitsPerPix==1 || cBitsPerPix==4 || cBitsPerPix==8 || cBitsPerPix==16 || cBitsPerPix==24 || cBitsPerPix==32); adjustedwidth = ((ds.dsBmih.biWidth * cBitsPerPix + 31) & ~31) / 8; nColors = ds.dsBmih.biClrUsed; if((nColors==0) && (cBitsPerPix<=8)) { nColors = 1 << cBitsPerPix; } Assert(ds.dsBmih.biCompression!=BI_BITFIELDS || nColors==0); dwColors = nColors*sizeof(RGBQUAD) + (ds.dsBmih.biCompression==BI_BITFIELDS?3*sizeof(DWORD):0); dwImage = ds.dsBmih.biHeight * adjustedwidth; if(fFileHeader) { BITMAPFILEHEADER bf; bf.bfType = 0x4D42; // "BM" bf.bfOffBits = sizeof(BITMAPFILEHEADER) + sizeof(BITMAPINFOHEADER) + dwColors; bf.bfSize = bf.bfOffBits + dwImage; bf.bfReserved1 = 0; bf.bfReserved2 = 0; hr = pStm->Write(&bf, sizeof(bf), &dw); if(hr) { goto Cleanup; } } hr = pStm->Write(&(ds.dsBmih), sizeof(BITMAPINFOHEADER), &dw); if(hr) { goto Cleanup; } if(nColors > 0) { RGBQUAD argb[256]; if(!hdcDibDst) { hdcDibDst = GetMemoryDC(); if(!hdcDibDst) { goto OutOfMemory; } hbmSavDst = (HBITMAP)SelectObject(hdcDibDst, hbm); } GetDIBColorTable(hdcDibDst, 0, min(256, nColors), argb); hr = pStm->Write(argb, dwColors, &dw); if(hr) { goto Cleanup; } } else if(ds.dsBmih.biCompression == BI_BITFIELDS) { hr = pStm->Write(ds.dsBitfields, dwColors, &dw); if(hr) { goto Cleanup; } } hr = pStm->Write(ds.dsBm.bmBits, dwImage, &dw); Cleanup: if(hbmSavDst) { SelectObject(hdcDibDst, hbmSavDst); } if(hdcDibDst) { ReleaseMemoryDC(hdcDibDst); } if(pibd) { delete pibd; } RRETURN(hr); OutOfMemory: hr = E_OUTOFMEMORY; goto Cleanup; }
void CImgCtx::TileSlow( HDC hdc, RECT* prc, LONG xDstOrg, LONG yDstOrg, SIZE* psizePrint, BOOL fOpaque, COLORREF crBack, IMGANIMSTATE* pImgAnimState, DWORD dwFlags) { LONG xDst = prc->left; LONG yDst = prc->top; LONG xDstWid = prc->right - xDst; LONG yDstHei = prc->bottom - yDst; LONG xFullWid= GetImgInfo()->_xWid; LONG yFullHei= GetImgInfo()->_yHei; LONG xSrcWid = psizePrint ? psizePrint->cx : xFullWid; LONG ySrcHei = psizePrint ? psizePrint->cy : yFullHei; LONG xPreWid, yPreHei, xSrcOrg, ySrcOrg; LONG xBltSrc, xBltDst, xBltDstWid, xBltWid, xBltSrcOrg; LONG yBltSrc, yBltDst, yBltDstHei, yBltHei, yBltSrcOrg; RECT rcSrc, rcDst, rcDstFull; HDC hdcMem = NULL; HBITMAP hbmMem = NULL; HBITMAP hbmSav = NULL; HRESULT hr = S_OK; if(xSrcWid==0 || ySrcHei==0 || xDstWid==0 || yDstHei==0) { return; } // Currently (xSrcOrg,ySrcOrg) define a point on the infinite plane of // the hdc where the upper-left corner of the image should be aligned. // Here we convert this point into offsets from the upper-left corner // of the image where the first pixel will be drawn as defined by prc. // That is, what is the coordinate of the pixel in the image which // will be drawn at the location (xDst,yDst). xSrcOrg = abs(xDst - xDstOrg) % xSrcWid; if(xDst<xDstOrg && xSrcOrg>0) { xSrcOrg = xSrcWid - xSrcOrg; } ySrcOrg = abs(yDst - yDstOrg) % ySrcHei; if(yDst<yDstOrg && ySrcOrg>0) { ySrcOrg = ySrcHei - ySrcOrg; } // If the source image is very small, it makes sense to pre-tile it // into an offscreen bitmap. The area of the destination needs to // be at least four times the area of the source. xPreWid = min(xSrcWid, xDstWid); yPreHei = min(ySrcHei, yDstHei); if(psizePrint || xPreWid*yPreHei>=PRETILE_AREA || xPreWid*yPreHei*4>xDstWid*yDstHei || (!fOpaque && crBack==CLR_INVALID)) { if(!psizePrint && !fOpaque && crBack!=CLR_INVALID) { PatBltBrush(hdc, prc, PATCOPY, crBack); } goto nopretile; } // Increase the dimensions of the pretile area as far as possible xPreWid = max(xPreWid, min(xDstWid, (PRETILE_AREA/(yPreHei*xSrcWid))*xSrcWid)); yPreHei = max(yPreHei, min(yDstHei, (PRETILE_AREA/(xPreWid*ySrcHei))*ySrcHei)); Assert(xPreWid*yPreHei <= PRETILE_AREA); Assert(xPreWid>0 && xPreWid<=xDstWid); Assert(yPreHei>0 && yPreHei<=yDstHei); hdcMem = GetMemoryDC(); if(hdcMem == NULL) { goto Cleanup; } hbmMem = CreateCompatibleBitmap(hdc, xPreWid, yPreHei); if(hbmMem == NULL) { goto Cleanup; } hbmSav = (HBITMAP)SelectObject(hdcMem, hbmMem); rcDst.left = 0; rcDst.top = 0; rcDst.right = xPreWid; rcDst.bottom = yPreHei; TileFast(hdcMem, &rcDst, xSrcWid-xSrcOrg, ySrcHei-ySrcOrg, fOpaque, crBack, pImgAnimState, dwFlags); xSrcOrg = 0; ySrcOrg = 0; xSrcWid = xPreWid; ySrcHei = yPreHei; nopretile: if(psizePrint) { // Remember the original image source sizes in xPreWid/yPreHei in // order to compute the rcSrc in pixels below. xPreWid = GetImgInfo()->_xWid; yPreHei = GetImgInfo()->_yHei; if(xPreWid==0 || yPreHei==0) { return; } } yBltDst = yDst; yBltDstHei = yDstHei; yBltSrcOrg = ySrcOrg; while(yBltDstHei) { yBltSrc = yBltSrcOrg; yBltHei = min(ySrcHei-yBltSrcOrg, yBltDstHei); xBltDst = xDst; xBltDstWid = xDstWid; xBltSrcOrg = xSrcOrg; while(xBltDstWid) { xBltSrc = xBltSrcOrg; xBltWid = min(xSrcWid-xBltSrcOrg, xBltDstWid); if(hdcMem) { BitBlt(hdc, xBltDst, yBltDst, xBltWid, yBltHei, hdcMem, xBltSrc, yBltSrc, SRCCOPY); } else { if(psizePrint) { rcSrc.left = MulDivQuick(xBltSrc, xPreWid, xSrcWid); rcSrc.top = MulDivQuick(yBltSrc, yPreHei, ySrcHei); rcSrc.right = MulDivQuick(xBltSrc+xBltWid, xPreWid, xSrcWid); rcSrc.bottom = MulDivQuick(yBltSrc+yBltHei, yPreHei, ySrcHei); } else { rcSrc.left = xBltSrc; rcSrc.top = yBltSrc; rcSrc.right = xBltSrc + xBltWid; rcSrc.bottom = yBltSrc + yBltHei; } rcDst.left = xBltDst; rcDst.top = yBltDst; rcDst.right = xBltDst + xBltWid; rcDst.bottom = yBltDst + yBltHei; rcDstFull.left = xBltDst - xBltSrc; rcDstFull.top = yBltDst - yBltSrc; rcDstFull.right = xBltDst - xBltSrc + xFullWid; rcDstFull.bottom = yBltDst - yBltSrc + yFullHei; if(pImgAnimState) { GetImgInfo()->DrawFrame(hdc, pImgAnimState, &rcDst, &rcSrc, &rcDstFull, dwFlags); } else { hr = GetImgInfo()->DrawImage(hdc, &rcDst, &rcSrc, SRCCOPY, dwFlags); if(hr) { goto Cleanup; } } } xBltDst += xBltWid; xBltDstWid -= xBltWid; xBltSrcOrg = 0; } yBltDst += yBltHei; yBltDstHei -= yBltHei; yBltSrcOrg = 0; } Cleanup: if(hbmSav) { SelectObject(hdcMem, hbmSav); } if(hbmMem) { DeleteObject(hbmMem); } if(hdcMem) { ReleaseMemoryDC(hdcMem); } }