📄 scgdiplusutils.cpp
字号:
pPen->SetDashStyle(DashStyleDashDot);
break;
case PS_DASHDOTDOT:
pPen->SetDashStyle(DashStyleDashDotDot);
break;
case PS_USERSTYLE:
pPen->SetDashStyle(DashStyleCustom);
// user-supplied style array pointed to by elpStyleEntry (limited to
// elpNumEntries elements) must be used to describe the custom pen
{
REAL* pReals = SCREALFromDWORD(pExtLogPen->elpStyleEntry, pExtLogPen->elpNumEntries);
// "The length of each dash and space in the dash pattern is the product of
// the element value in the array and the width of the Pen object."
// So now we must devide somehow.
// But I'm not sure the method coded here is bullet proof, since I should
// use what GDI calls "style units" to make the division. But listen:
// "If you absolutely have to know the style unit, the application must draw a styled
// line in a bitmap and read it back to determine the size of the style units
// in the x and y directions".
if (0==iWidth)
iWidth = 1;
for (UINT i=0; (i<pExtLogPen->elpNumEntries); i++)
{
pReals[i] = pReals[i]/(REAL)iWidth;
}
pPen->SetDashPattern(pReals, pExtLogPen->elpNumEntries);
delete [] pReals;
}
break;
case PS_INSIDEFRAME:
// comments in SCPenFromLogPen
pPen->SetDashStyle(DashStyleSolid);
pPen->SetAlignment(PenAlignmentInset);
break;
case PS_ALTERNATE:
// Windows NT/2000/XP: we don't have the corresponding style in GDI+, so just pray.
// fall through
default:
pPen->SetDashStyle(DashStyleSolid);
ASSERT(0);
}
if (PS_GEOMETRIC==iPenType)
{
// Lines joint (applies only to PS_GEOMETRIC pens in GDI)
switch (pExtLogPen->elpPenStyle & PS_JOIN_MASK)
{
case PS_JOIN_ROUND:
pPen->SetLineJoin(LineJoinRound);
break;
case PS_JOIN_MITER:
pPen->SetLineJoin(LineJoinMiter);
break;
case PS_JOIN_BEVEL:
pPen->SetLineJoin(LineJoinBevel);
break;
default:
// (cf. MSDN "Pens in Win32")
pPen->SetLineJoin(LineJoinRound);
ASSERT(0);
}
// End cap (applies only to PS_GEOMETRIC pens in GDI)
switch (pExtLogPen->elpPenStyle & PS_ENDCAP_MASK)
{
case PS_ENDCAP_ROUND:
pPen->SetLineCap(LineCapRound, LineCapRound, DashCapRound);
break;
case PS_ENDCAP_FLAT:
pPen->SetLineCap(LineCapFlat, LineCapFlat, DashCapFlat);
break;
case PS_ENDCAP_SQUARE:
pPen->SetLineCap(LineCapSquare, LineCapSquare, DashCapFlat);
break;
default:
// (cf. MSDN "Pens in Win32")
pPen->SetLineCap(LineCapRound, LineCapRound, DashCapRound);
ASSERT(0);
}
// "all [brush related] members must be used to specify the brush
// attributes of the pen".
if ((BS_HOLLOW!=pExtLogPen->elpBrushStyle) &&
(BS_SOLID!=pExtLogPen->elpBrushStyle || PS_SOLID!=iPenStyle))
{
LOGBRUSH LogBrush;
LogBrush.lbStyle = pExtLogPen->elpBrushStyle;
LogBrush.lbColor = pExtLogPen->elpColor;
LogBrush.lbHatch = pExtLogPen->elpHatch;
BOOL bSvd = rDCState.bMonoBrush;
Brush* pBrush = SCBrushFromLogBrush(LogBrush, rDCState);
if (pBrush)
pPen->SetBrush(pBrush);
rDCState.bMonoBrush = bSvd;
}
}
// else PS_COSMETIC:
// "the [pExtLogPen->elpColor] member specifies the color of the pen and the
// [pExtLogPen->elpPenStyle] member must be set to BS_SOLID"
return pPen;
}
///
/// Fill a two-color palette with current text/background colors of DC.
/// (For monochrome brush color realization)
///
void SCFillMonochromePalette(SCShortDCState& rDCState, PPALETTEENTRY palPalEntry)
{
ASSERT(palPalEntry);
COLORREF crBkColor = rDCState.crBkColor;
COLORREF crTextColor = rDCState.crTextColor;
palPalEntry[0].peRed = GetRValue(crTextColor);
palPalEntry[0].peGreen = GetGValue(crTextColor);
palPalEntry[0].peBlue = GetBValue(crTextColor);
palPalEntry[0].peFlags = 0;
palPalEntry[1].peRed = GetRValue(crBkColor);
palPalEntry[1].peGreen = GetGValue(crBkColor);
palPalEntry[1].peBlue = GetBValue(crBkColor);
palPalEntry[1].peFlags = 0;
}
///
/// Attach a two-color palette to a GDI+ image, using the given colors.
///
inline BOOL SCSetMonochromeImagePalette(Image* pImage, COLORREF crTextColor, COLORREF crBkColor)
{
ASSERT(pImage);
BOOL bOk = FALSE;
// Update color palette for 1-bpp.
ColorPalette* pPal = (ColorPalette*)new BYTE[sizeof(ColorPalette) + 2*sizeof(ARGB)];
pPal->Flags = PaletteFlagsHasAlpha;
pPal->Count = 2;
pPal->Entries[0] = Color::MakeARGB(255, GetRValue(crTextColor),
GetGValue(crTextColor),
GetBValue(crTextColor));
pPal->Entries[1] = Color::MakeARGB(255, GetRValue(crBkColor),
GetGValue(crBkColor),
GetBValue(crBkColor));
bOk = (pImage->SetPalette(pPal)==Ok);
delete [] (BYTE*)pPal;
return bOk;
}
///
/// Attach a two-color palette to a GDI+ image, using current text and background color.
///
inline BOOL SCSetMonochromeBrushPalette(Image* pImage, SCShortDCState& rDCState)
{
ASSERT(pImage);
return SCSetMonochromeImagePalette(pImage, rDCState.crTextColor, rDCState.crBkColor);
}
///
/// Attach a two-color palette to a GDI+ image, using the DC state colors.
///
Brush* SCRealizeMonochromeBrushPalette(Brush* pBrush, SCShortDCState& rDCState)
{
ASSERT(pBrush && pBrush->GetType()==BrushTypeTextureFill);
if (!pBrush || pBrush->GetType()!=BrushTypeTextureFill)
return NULL;
// Well, the bitmap stored in the brush isn't 1bpp anymore
// And setting palette on 32bpp bitmap will silently fail
Bitmap* pBitmap = (Bitmap*)((TextureBrush*)pBrush)->GetImage(); // a 32bpp (a plain copy, not a "just to see" pointer)
ASSERT(pBitmap && pBitmap->GetLastStatus()==Ok);
#if 0
// This too fails. "Jeez!... it's full of 'stars!'"
Bitmap* pClone = pBitmap->Clone(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight(), PixelFormat1bppIndexed);
#else
// Manual cloning => bad/funny results
// LockBits doesn't understand that WE WANT PixelFormat1bppIndexed!
// "LockBits [...]
// format
// [in] Integer that specifies the format of the pixel data in the temporary buffer.
// The pixel format of the temporary buffer does not have to be the same as the pixel
// format of this Bitmap object. The PixelFormat data type and constants that represent
// various pixel formats are defined in Gdipluspixelformats.h. For more information about
// pixel format constants, see Image Pixel Format Constants.
// Microsoft Windows GDI+ version 1.0 does not support processing of 16-bits-per-channel
// images, so you should not set this parameter equal to PixelFormat48bppRGB,
// PixelFormat64bppARGB, or PixelFormat64bppPARGB."
// You can add PixelFormat1bppIndexed to the list.
BitmapData BmData;
Rect rect(0, 0, pBitmap->GetWidth(), pBitmap->GetHeight());
Status iRes = pBitmap->LockBits(&rect, ImageLockModeRead,
PixelFormat32bppARGB/*oops!*/, &BmData);
ASSERT(iRes==Ok);
Bitmap* pClone = new Bitmap(pBitmap->GetWidth(), pBitmap->GetHeight(),
BmData.Stride, PixelFormat1bppIndexed, (BYTE*)BmData.Scan0);
pBitmap->UnlockBits(&BmData);
#endif
ASSERT(pBitmap->GetLastStatus()==Ok);
ASSERT(pClone && pClone->GetLastStatus()==Ok);
BOOL bOk = SCSetMonochromeImagePalette(pClone, rDCState.crTextColor, rDCState.crBkColor);
TextureBrush* pNewBrush = NULL;
if (bOk)
{
// We can't just set
//((TextureBrush*)pBrush)->SetBitmap(pClone);
Matrix matrix;
((TextureBrush*)pBrush)->GetTransform(&matrix);
pNewBrush = new TextureBrush(pClone);
if (pNewBrush)
{
Status iRes = pNewBrush->SetTransform(&matrix);
ASSERT(iRes==Ok);
}
}
delete pClone;
delete pBitmap; // warning!?
return pNewBrush;
}
#if 0
///
/// Create a GDI+ font from a GDI LOGFONT.
///
Font* SCFontFromLogFont(LOGFONT& rLogFont)
{
ASSERT(0); // not implemented
return NULL;
}
#endif
///
/// Build an TrueType approximation of the font describes in LogFont.
/// Note, this is a late font substitution (more complicated).
///
HFONT SCTTFontFromLOGFONT(LOGFONT& rLogFont, HDC hDC)
{
rLogFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
rLogFont.lfPitchAndFamily |= SCFontFamilyApproximant((TCHAR*)rLogFont.lfFaceName);
HFONT hFont = CreateFontIndirect(&rLogFont);
ASSERT(hFont);
if (!hFont)
{// silent failure
switch (rLogFont.lfPitchAndFamily & 0xF0)
{
case FF_ROMAN:
_tcscpy((TCHAR*)rLogFont.lfFaceName, _T("Times New Roman"));
break;
case FF_DONTCARE:
case FF_SWISS:
case FF_MODERN:
case FF_SCRIPT:
case FF_DECORATIVE:
default:
_tcscpy((TCHAR*)rLogFont.lfFaceName, _T("Arial"));
}
return NULL;
}
BOOL bTmpDC = (NULL==hDC);
if (bTmpDC)
hDC = ::GetDC(NULL);
ASSERT(hDC);
HFONT hOldFont = (HFONT)SelectObject(hDC, hFont);
GetTextFace(hDC, LF_FACESIZE, rLogFont.lfFaceName);
if (bTmpDC)
{// no DC was given for selecting font
SelectObject(hDC, hOldFont);
ReleaseDC(NULL,hDC);
} // else the returned font is selected in the DC
// the danger is we are losing hOldFont
return hFont;
}
///
/// Create an array of GDI+ Points from an array of Win32 POINTs.
///
// Point* SCPointFromPOINT(LPCPOINT pPoints, DWORD dwCount)
template <class T>
Point* SCPointFromPOINT(T pPoints, DWORD dwCount)
{
ASSERT(pPoints && dwCount);
Point *pPts = new Point[dwCount];
Point *pDest = pPts;
Point *pLimit = pDest + dwCount;
for(; (pDest<pLimit); pDest++, pPoints++)
{
pDest->X = pPoints->x;
pDest->Y = pPoints->y;
}
return pPts;
}
// some explicit instantiations, cause it's a library
template Point* SCPointFromPOINT<LPPOINT>(LPPOINT, DWORD);
template Point* SCPointFromPOINT<LPPOINTS>(LPPOINTS, DWORD);
//
///
/// Create an array of GDI+ Points from an array of Win32 POINTSs completed by the
/// current position in play DC (hold in rPtStart).
///
template <class T>
Point* SCPointFromPOINTTo(Point& rPtStart, T pPoints, DWORD dwCount)
{
ASSERT(pPoints && dwCount);
// add +1 to count to include the current position in DC
Point *pPts = new Point[++dwCount];
// copy first point
pPts->X = rPtStart.X;
pPts->Y = rPtStart.Y;
// copy other points
Point *pDest = pPts + 1;
Point *pLimit = pPts + dwCount;
for(; (pDest<pLimit); pDest++, pPoints++)
{
pDest->X = pPoints->x;
pDest->Y = pPoints->y;
}
return pPts;
}
// some explicit instantiations, cause it's a library
template Point* SCPointFromPOINTTo<LPPOINT>(Point&, LPPOINT, DWORD);
template Point* SCPointFromPOINTTo<LPPOINTS>(Point&, LPPOINTS, DWORD);
//
///
/// Create an array of REALs from an array of DWORDs.
///
REAL* SCREALFromDWORD(LPDWORD pDWords, DWORD dwCount)
{
ASSERT(pDWords && dwCount);
REAL *pReals = new REAL[dwCount];
REAL *pDest = pReals;
REAL *pLimit = pDest + dwCount;
while (pDest<pLimit)
{
*pDest++ = (REAL)*pDWords++;
}
return pReals;
}
///
/// Translate GDI clipping modes into GDI+ equivalent.
///
CombineMode SCClipModeFormRGNMode(INT iMode)
{
switch (iMode)
{
case RGN_COPY:
return CombineModeReplace;
case RGN_AND:
return CombineModeIntersect;
case RGN_DIFF:
return CombineModeExclude;
case RGN_OR:
return CombineModeUnion;
case RGN_XOR:
return CombineModeXor;
default:
ASSERT(0);
}
return CombineModeReplace;
}
///
/// Perfom a rop opeartion by filling a rectangle with the color located at
/// the given index in the default system palette. (WHITENESS/BLACKNESS)
///
void SCSysPaletteFillRect(I_SCDCGraphics* pIGraphics, Rect& destRect, UINT uiPalIndex)
{
ASSERT(pIGraphics);
ASSERT(uiPalIndex<256);
PALETTEENTRY PaletteEntry;
// Bogus GDI documentation?: index 1 doesn't correspond to WHITENESS as expected
// (And we know that the 20 static colors (reserved) use the following indices:
// 0-9, 246-255; but that's true for Windows 3.0 and 3.1; for other systems, !!??)
//
// So, consider using manual colors.
HDC hdc = GetDC(NULL);
GetSystemPaletteEntries (hdc, uiPalIndex, 1, &PaletteEntry);
ReleaseDC(NULL, hdc);
Color BrushColor;
BrushColor.SetFromCOLORREF(pIGraphics->SCGetFinalColor(RGB(PaletteEntry.peRed,
PaletteEntry.peGreen,
PaletteEntry.peBlue)));
SolidBrush brush(BrushColor);
Graphics* pGraphics = pIGraphics->SCGetGraphics();
ASSERT(pGraphics);
pGraphics->FillRectangle(&brush, destRect);
}
///
/// Perfom a DIB blt opeartion using ROP.
///
INT SCStretchDIBits(
I_SCDCGraphics* pIGraphics, // pointer to destination graphics context
INT XDest, // x-coordinate of upper-left corner of dest. rectangle
INT YDest, // y-coordinate of upper-left corner of dest. rectangle
INT nDestWidth, // width of destination rectangle
INT nDestHeight, // height of destination rectangle
INT XSrc, // x-coordinate of upper-left corner of source rectangle
INT YSrc, // y-coordinate of upper-left corner of source rectangle
INT nSrcWidth, // width of source rectangle
INT nSrcHeight, // height of source rectangle
CONST VOID *lpBits, // address of bitmap bits
CONST BITMAPINFO *lpBitsInfo, // address of bitmap data
UINT iUsage, // usage flags
DWORD dwRop // raster operation code
)
{
ASSERT(pIGraphics);
// Prepare the temporary destination bitmap
HDC hOutputDC = pIGraphics->SCGetDC();
ASSERT(hOutputDC);
if (!hOutputDC)
return FALSE;
HDC hDestDC = CreateCompatibleDC(hOutputDC);
#if 0
// best quality (but memory hog, and time consuming for GDI+, not for GDI)
INT iTmpWidth = nSrcWidth;
INT iTmpHeight = nSrcHeight;
#else
// faster (but less smooth image)
INT iTmpWidth = abs(nSrcWidth);
INT iTmpHeight = abs(nSrcHeight);
if (iTmpWidth>=1000 || iTmpHeight>=1000) // TODO: fix these arbitrary values
{// large high resolution bitmaps will bog down GDI+
// (it won't crash, but it can take 5 minutes, and generate 250Mo memory peaks)
iTmpWidth = abs(nDestWidth);
iTmpHeight = abs(nDestHeight);
// inflate dest to enhance quality
if (iTmpWidth<500 && iTmpHeight<500)
{
iTmpWidth *= 2;
iTmpHeight *= 2;
}
}
#endif
HBITMAP hDestBmp = CreateCompatibleBitmap(hOutputDC, iTmpWidth, iTmpHeight);
if (!hDestBmp)
{
DWORD dwError = GetLastError();
ASSERT(0);
}
HBITMAP hOldBmp = (HBITMAP)SelectObject(hDestDC, hDestBmp);
// Copy the destination rectangle
BOOL bOK = StretchBlt(hDestDC, 0, 0, iTmpWidth, iTmpHeight,
hOutputDC, XDest, YDest, nDestWidth, nDestHeight, SRCCOPY);
if (!bOK)
{// Maybe failure due to rotation/shear found in hOutputDC
// (do a manual resampling of the destination rectangle)
float pitchx = float(nDestWidth)/float(iTmpWidth);
float pitchy = float(nDestHeight)/float(iTmpHeight);
int ys;
for (int y=0; (y<iTmpHeight); y++)
{
ys = (int)(YDest + y*pitchy);
int xs;
for (int x=0; (x<iTmpWidth); x++)
{
xs = (int)(XDest + x*pitchx);
COLORREF crColor = GetPixel(hOutputDC, xs, ys);
SetPixel(hDestDC, x, y, crColor);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -