#include "stdafx.h" #include "global.h" #include "pbrush.h" #include "pbrusdoc.h" #include "pbrusfrm.h" #include "pbrusvw.h" #include "minifwnd.h" #include "bmobject.h" #include "imgsuprt.h" #include "imgwnd.h" #include "imgbrush.h" #include "imgwell.h" #include "imgtools.h" #include "t_fhsel.h" #include "toolbox.h" #include "mmsystem.h" #ifdef _DEBUG #undef THIS_FILE static CHAR BASED_CODE THIS_FILE[] = __FILE__; #endif #include "memtrace.h" CImgBrush theImgBrush; CImgBrush::CImgBrush() : m_bCuttingFromImage(FALSE), m_bOpaque(TRUE) { } CImgBrush::~CImgBrush() { // cleanup old region if exists if (m_cRgnPolyFreeHandSel.GetSafeHandle() != NULL) m_cRgnPolyFreeHandSel.DeleteObject(); if (m_cRgnPolyFreeHandSelBorder.GetSafeHandle() != NULL) m_cRgnPolyFreeHandSelBorder.DeleteObject(); if (m_hbmOld) m_dc.SelectObject( CBitmap::FromHandle( m_hbmOld ) ); if (m_hbmMaskOld) m_dc.SelectObject( CBitmap::FromHandle( m_hbmMaskOld ) ); m_dc.DeleteDC(); m_bitmap.DeleteObject(); m_maskDC.DeleteDC(); m_maskBitmap.DeleteObject(); } BOOL CImgBrush::CopyTo(CImgBrush& destBrush) { if (destBrush.m_hbmOld) destBrush.m_dc.SelectObject( CBitmap::FromHandle( destBrush.m_hbmOld ) ); if (destBrush.m_hbmMaskOld) destBrush.m_maskDC.SelectObject( CBitmap::FromHandle( destBrush.m_hbmMaskOld ) ); destBrush.m_hbmOld = NULL; destBrush.m_hbmMaskOld = NULL; destBrush.m_dc.DeleteDC(); destBrush.m_bitmap.DeleteObject(); destBrush.m_maskDC.DeleteDC(); destBrush.m_maskBitmap.DeleteObject(); if (m_dc.m_hDC != NULL) { if (! destBrush.m_dc.CreateCompatibleDC( NULL ) || ! destBrush.m_bitmap.CreateCompatibleBitmap(&m_dc, m_size.cx, m_size.cy)) { theApp.SetGdiEmergency(FALSE); return FALSE; } destBrush.m_hbmOld = (HBITMAP)((destBrush.m_dc.SelectObject( &destBrush.m_bitmap ))->GetSafeHandle()); CPalette* ppalOldSrc = SetBrushPalette( &m_dc, TRUE ); // Background ?? CPalette* ppalOldDest = SetBrushPalette( &destBrush.m_dc, TRUE ); // Background ?? destBrush.m_dc.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, SRCCOPY ); if (ppalOldSrc) m_dc.SelectPalette( ppalOldSrc, TRUE ); // Background ?? if (ppalOldDest) destBrush.m_dc.SelectPalette( ppalOldDest, TRUE ); // Background ?? } if (m_maskDC.m_hDC != NULL) { if (! destBrush.m_maskDC.CreateCompatibleDC(NULL) || ! destBrush.m_maskBitmap.CreateCompatibleBitmap(&m_maskDC, m_size.cx, m_size.cy)) { theApp.SetGdiEmergency(FALSE); return FALSE; } destBrush.m_hbmMaskOld = (HBITMAP)((destBrush.m_maskDC.SelectObject( &destBrush.m_maskBitmap))->GetSafeHandle()); destBrush.m_maskDC.BitBlt(0, 0, m_size.cx, m_size.cy, &m_maskDC, 0, 0, SRCCOPY); } destBrush.m_size = m_size; destBrush.m_bFirstDrag = m_bFirstDrag; destBrush.m_bLastDragWasASmear = m_bLastDragWasASmear; destBrush.m_bLastDragWasFirst = m_bLastDragWasFirst; destBrush.m_bMakingSelection = m_bMakingSelection; destBrush.m_bMoveSel = m_bMoveSel; destBrush.m_bSmearSel = m_bSmearSel; destBrush.m_bOpaque = m_bOpaque; destBrush.m_rcDraggedFrom = m_rcDraggedFrom; destBrush.m_pImg = m_pImg; destBrush.m_rcSelection = m_rcSelection; destBrush.m_handle = m_handle; return TRUE; } void CImgBrush::CenterHandle() { m_handle.cx = m_size.cx / 2; m_handle.cy = m_size.cy / 2; } void CImgBrush::TopLeftHandle() { m_handle.cx = 0; m_handle.cy = 0; } CPalette* CImgBrush::SetBrushPalette( CDC* pdc, BOOL bForce ) { CPalette* ppal = NULL; CPalette* ppalOld = NULL; if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) ppal = theApp.m_pPalette; if (ppal != NULL) { ppalOld = pdc->SelectPalette( ppal, bForce ); pdc->RealizePalette(); } return ppalOld; } HPALETTE CImgBrush::SetBrushPalette( HDC hdc, BOOL bForce ) { CPalette* ppal = NULL; HPALETTE hpalOld = NULL; if (theApp.m_pPalette && theApp.m_pPalette->m_hObject) ppal = theApp.m_pPalette; if (ppal != NULL) { hpalOld = ::SelectPalette( hdc, (HPALETTE)ppal->m_hObject, bForce ); RealizePalette( hdc ); } return hpalOld; } BOOL CImgBrush::SetSize( CSize newSize, BOOL bStretchToFit ) { BOOL bFlipX; BOOL bFlipY; if (newSize.cx == m_size.cx && newSize.cy == m_size.cy) return TRUE; if (bFlipX = (newSize.cx < 0)) newSize.cx = -newSize.cx; if (bFlipY = (newSize.cy < 0)) newSize.cy = -newSize.cy; if (newSize.cx == 0) newSize.cx = 1; if (newSize.cy == 0) newSize.cy = 1; if (CImgTool::GetCurrentID() != IDMX_TEXTTOOL) { CDC newDC; CBitmap newBitmap; CDC newMaskDC; CBitmap newMaskBitmap; //REARCHITECT Potential for DC && Bitmap leaks here on partial failure!! if (! newDC.CreateCompatibleDC ( &m_dc ) || ! newBitmap.CreateCompatibleBitmap( &m_dc, newSize.cx, newSize.cy ) || ! newMaskDC.CreateCompatibleDC ( &m_dc ) || ! newMaskBitmap.CreateBitmap(newSize.cx, newSize.cy, 1, 1, NULL )) return FALSE; CBitmap* pbmOld = newDC.SelectObject( &newBitmap ); CPalette* ppalOldSrc = SetBrushPalette( &m_dc, FALSE ); CPalette* ppalOldDest = SetBrushPalette( &newDC, FALSE ); newDC.SetStretchBltMode(COLORONCOLOR); if (bStretchToFit) { StretchCopy( newDC.m_hDC, bFlipX ? newSize.cx : 0, bFlipY ? newSize.cy : 0, bFlipX ? -newSize.cx : newSize.cx, bFlipY ? -newSize.cy : newSize.cy, m_dc.m_hDC, 0, 0, m_size.cx, m_size.cy ); } else { StretchCopy( newDC.m_hDC, bFlipX ? newSize.cx : 0, bFlipY ? newSize.cy : 0, m_size.cx, m_size.cy, m_dc.m_hDC, 0, 0, m_size.cx, m_size.cy ); } COLORREF crOldBk = newDC.SetBkColor( crRight ); CBitmap* pbmOldMask = newMaskDC.SelectObject( &newMaskBitmap ); if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL) { CFreehandSelectTool* pTool = (CFreehandSelectTool*)CImgTool::GetCurrent(); if (pTool->ExpandPolyRegion( newSize.cx, newSize.cy )) { newMaskDC.PatBlt( 0, 0, newSize.cx, newSize.cy, BLACKNESS ); if (m_cRgnPolyFreeHandSel.GetSafeHandle()) newMaskDC.FillRgn( &m_cRgnPolyFreeHandSel, CBrush::FromHandle( (HBRUSH)::GetStockObject( WHITE_BRUSH ) ) ); } } else { newMaskDC.PatBlt( 0, 0, newSize.cx, newSize.cy, WHITENESS ); } newMaskDC.BitBlt( 0, 0, newSize.cx, newSize.cy, &newDC, 0, 0, DSna ); newDC.SetBkColor( crOldBk ); if (ppalOldSrc) m_dc.SelectPalette( ppalOldSrc, FALSE ); if (ppalOldDest) newDC.SelectPalette( ppalOldDest, FALSE ); if (m_hbmOld) m_dc.SelectObject( CBitmap::FromHandle( m_hbmOld ) ); if (m_hbmMaskOld) m_maskDC.SelectObject( CBitmap::FromHandle( m_hbmMaskOld ) ); m_dc.DeleteDC(); m_maskDC.DeleteDC(); m_bitmap.DeleteObject(); m_maskBitmap.DeleteObject(); m_dc.Attach( newDC.Detach() ); m_bitmap.Attach( newBitmap.Detach() ); m_maskDC.Attach( newMaskDC.Detach() ); m_maskBitmap.Attach( newMaskBitmap.Detach() ); m_hbmOld = (HBITMAP)(pbmOld->GetSafeHandle()); m_hbmMaskOld = (HBITMAP)(pbmOldMask->GetSafeHandle()); } m_size.cx = newSize.cx; m_size.cy = newSize.cy; return TRUE; } #if defined(DEBUGSHOWBITMAPS) void DebugShowBitmap(HDC hdcSrc, int x, int y, int wid, int hgt) { HDC hdcDst = GetDC(NULL); BitBlt(hdcDst, 0, 0, wid, hgt, hdcSrc, x, y, SRCCOPY); ReleaseDC(NULL, hdcDst); } #endif BOOL QuickColorToMono(CDC* pdcMono, int xMono, int yMono, int cx, int cy, CDC *pdcColor, int xColor, int yColor, DWORD dwROP, COLORREF crTrans) { RGBQUAD rgb[256]; int nColors = GetDIBColorTable(pdcColor->m_hDC, 0, 256, &rgb[0]); if (nColors == 0) { return(FALSE); } RGBQUAD rgbWhite; rgbWhite.rgbRed = 255; rgbWhite.rgbGreen = 255; rgbWhite.rgbBlue = 255; rgbWhite.rgbReserved = 0; RGBQUAD rgbBlack; rgbBlack.rgbRed = 0; rgbBlack.rgbGreen = 0; rgbBlack.rgbBlue = 0; rgbBlack.rgbReserved = 0; RGBQUAD rgbTemp[256]; switch ((BYTE)((crTrans)>>24)) { case 0: case 2: { RGBQUAD rgbTrans; rgbTrans.rgbRed = GetRValue(crTrans); rgbTrans.rgbGreen = GetGValue(crTrans); rgbTrans.rgbBlue = GetBValue(crTrans); rgbTrans.rgbReserved = 0; for (int nColor=nColors-1; nColor>=0; --nColor) { if (memcmp(&rgb[nColor], &rgbTrans, sizeof(rgbTrans)) == 0) { rgbTemp[nColor] = rgbWhite; } else { rgbTemp[nColor] = rgbBlack; } } break; } // We can put support for different COLORREF formats here default: return(FALSE); } SetDIBColorTable(pdcColor->m_hDC, 0, nColors, &rgbTemp[0]); pdcMono->BitBlt(xMono, yMono, cx, cy, pdcColor, xColor, yColor, dwROP); SetDIBColorTable(pdcColor->m_hDC, 0, nColors, &rgb[0]); return(TRUE); } #define COLORTOMONOBUG #ifdef COLORTOMONOBUG void CImgBrush::ColorToMonoBitBlt(CDC* pdcMono, int xMono, int yMono, int cx, int cy, CDC *pdcColor, int xColor, int yColor, DWORD dwROP, COLORREF transparentColor) { if (QuickColorToMono(pdcMono, xMono, yMono, cx, cy, pdcColor, xColor, yColor, dwROP, transparentColor)) { return; } CDC dcColor; CTempBitmap bmColor; CBitmap* pbmOldColor = NULL; // Use a moderate-sized intermediate bitmap int cyStep = 0xffff / cx; cyStep = max(1, min(cy, cyStep)); HDC hdcScreen = GetDC(NULL); BOOL bError = (!dcColor.CreateCompatibleDC(NULL) || !bmColor.CreateCompatibleBitmap(CDC::FromHandle(hdcScreen), cx, cyStep) || (pbmOldColor = dcColor.SelectObject(&bmColor))==NULL); ReleaseDC(NULL, hdcScreen); if (bError) { theApp.SetGdiEmergency(FALSE); return; } CPalette* ppalOld = SetBrushPalette( pdcColor, FALSE ); CPalette* ppalOldColor = SetBrushPalette( &dcColor, FALSE ); dcColor.SetBkColor( transparentColor ); int yStep; for (yStep=0; yStep cy - yStep) { cyStep = cy - yStep; } dcColor.BitBlt(0, 0, cx, cyStep, pdcColor, xColor, yColor+yStep, SRCCOPY); pdcMono->BitBlt(xMono, yMono+yStep, cx, cyStep, &dcColor, 0, 0, dwROP); DebugShowBitmap(pdcMono->m_hDC, xMono, yMono, cx, cy); } if (ppalOld) { pdcColor->SelectPalette( ppalOld, FALSE ); } dcColor.SelectObject(pbmOldColor); if (ppalOldColor) { dcColor.SelectPalette( ppalOldColor, FALSE ); } } #endif // COLORTOMONOBUG void CImgBrush::RecalcMask( COLORREF transparentColor ) { if (! m_dc.GetSafeHdc() || ! m_maskDC.m_hDC) return; #ifndef COLORTOMONOBUG CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE ); COLORREF oldBkColor = m_dc.SetBkColor( transparentColor ); #endif // COLORTOMONOBUG if (CImgTool::GetCurrentID() == IDMB_PICKRGNTOOL) { m_maskDC.PatBlt( 0, 0, m_size.cx, m_size.cy, BLACKNESS ); if (m_cRgnPolyFreeHandSel.GetSafeHandle()) m_maskDC.FillRgn( &m_cRgnPolyFreeHandSel, CBrush::FromHandle( (HBRUSH)::GetStockObject( WHITE_BRUSH ) ) ); if (! m_bOpaque) // can't test true, since bitfield #ifdef COLORTOMONOBUG ColorToMonoBitBlt(&m_maskDC, 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, DSna, transparentColor); #else // COLORTOMONOBUG m_maskDC.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, DSna ); #endif // COLORTOMONOBUG } else { #ifdef COLORTOMONOBUG ColorToMonoBitBlt(&m_maskDC, 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, NOTSRCCOPY, transparentColor); #else // COLORTOMONOBUG m_maskDC.BitBlt( 0, 0, m_size.cx, m_size.cy, &m_dc, 0, 0, NOTSRCCOPY ); #endif // COLORTOMONOBUG } #ifndef COLORTOMONOBUG m_dc.SetBkColor( oldBkColor ); if (ppalOld) m_dc.SelectPalette( ppalOld, FALSE ); #endif // COLORTOMONOBUG } void GetMonoBltColors(HDC hDC, HBITMAP hBM, COLORREF& crNewBk, COLORREF& crNewText) { crNewBk = RGB(0xff, 0xff, 0xff); crNewText = RGB(0x00, 0x00, 0x00); RGBQUAD rq; if (GetDIBColorTable(hDC, 0, 1, &rq) == 1) { if (hBM == NULL) { hBM = (HBITMAP) GetCurrentObject(hDC, OBJ_BITMAP); } WORD nMaxIndex = 0xff; BITMAP bm; if (GetObject(hBM, sizeof(bm), &bm)) { nMaxIndex = (1 << bm.bmBitsPixel) - 1; } crNewBk = DIBINDEX(nMaxIndex); crNewText = DIBINDEX(0x00); } } // This handles drawing the brush with Draw Opaque turned off. // void CImgBrush::BltMatte(IMG* pimg, CPoint topLeft) { COLORREF crNewBk, crNewText; GetMonoBltColors(pimg->hDC, pimg->hBitmap, crNewBk, crNewText); COLORREF crOldBk = SetBkColor(pimg->hDC, crNewBk); COLORREF crOldText = SetTextColor(pimg->hDC, crNewText); CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE ); // Background ?? // Copying from a bitmap... DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_dc.m_hDC, 0, 0, DSx); DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_maskDC.m_hDC, 0, 0, DSna); DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_dc.m_hDC, 0, 0, DSx); DebugShowBitmap(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy); if (ppalOld) m_dc.SelectPalette( ppalOld, FALSE ); // Background ?? SetBkColor(pimg->hDC, crOldBk); SetTextColor(pimg->hDC, crOldText); } // This handles drawing the brush with Draw Opaque turned on. // void CImgBrush::BltReplace(IMG* pimg, CPoint topLeft) { int iToolID = CImgTool::GetCurrentID(); if (iToolID == IDMB_PICKRGNTOOL) { BltMatte( pimg, topLeft ); } else { CPalette* ppalOld = SetBrushPalette( &m_dc, FALSE ); // Background ?? BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_dc.m_hDC, 0, 0, SRCCOPY); if (ppalOld) m_dc.SelectPalette( ppalOld, FALSE ); // Background ?? } } // This handles erasing with the brush (draws mask in solid color). // void CImgBrush::BltColor(IMG* pimg, CPoint topLeft, COLORREF color) { COLORREF crOldBk = SetBkColor(pimg->hDC, color); COLORREF crOldText = SetTextColor(pimg->hDC, RGB(0, 0, 0)); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_maskDC.m_hDC, 0, 0, DSx); SetBkColor(pimg->hDC, RGB(255, 255, 255)); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_maskDC.m_hDC, 0, 0, DSna); SetBkColor(pimg->hDC, color); BitBlt(pimg->hDC, topLeft.x, topLeft.y, m_size.cx, m_size.cy, m_maskDC.m_hDC, 0, 0, DSx); SetTextColor(pimg->hDC, crOldText); SetBkColor(pimg->hDC, crOldBk); }