⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 scgdiplusutils.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 4 页
字号:
/*
*	This file is part of the EMFexplorer projet.
*	Copyright (C) 2004 Smith Charles.
*
*	This library is free software; you can redistribute it and/or
*	modify it under the terms of the GNU Lesser General Public
*	License as published by the Free Software Foundation; either
*	version 2.1 of the License, or (at your option) any later version.
*
*   This library is distributed in the hope that it will be useful,
*   but WITHOUT ANY WARRANTY; without even the implied warranty of
*   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
*   Lesser General Public License for more details.
*
*   You should have received a copy of the GNU Lesser General Public
*   License along with this library; if not, write to the Free Software
*   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA.
*
*	Extension: for commercial use, apply the Equity Public License, which
*	adds to the normal terms of the GLPL a condition of donation to the author.
*   If you are interested in support for this source code,
*   contact Smith Charles <smith.charles@free.fr> for more information.
*/


#include "stdafx.h"
#include "SCGdiplusUtils.h"
#include "SCEMF.h"
#include "SCEMFRasterizer.h"
#include "SCFileTypes.h"

#include "SCGenInclude.h"
#include SC_INC_WINLIB(SCMemDC.h)
#include SC_INC_WINLIB(SCBitmap.h)
#include SC_INC_WINLIB(MSDib.h)
#include SC_INC_WINLIB(SCGDIUtils.h)
#include SC_INC_GENLIB(SCGenMath.h)
#include <float.h>


// GDI+ won't allow DEBUG_NEW to work
//	#ifdef _DEBUG
//	#define new DEBUG_NEW
//	#undef THIS_FILE
//	static char THIS_FILE[] = __FILE__;
//	#endif

///
/// Create a GDI+ bitmap from a packed DIB (a pointer to a
/// BITMAPINFO structure immediately followed by the array of bytes that define
/// the pixels of the bitmap).
///
Bitmap* SCBitmapFromPtr(LPCBYTE pBytes)
{
	ASSERT(pBytes);
	if (!pBytes)
		return NULL;
	// get the BITMAPINFO
	BITMAPINFO* pBmi = (BITMAPINFO*)pBytes;

	// Locate the bits after the color table:
	// Since the DIB is packed, the biClrUsed member must be either zero or
	// the actual size of the color table
	BYTE* pBits = (BYTE*)pBmi + pBmi->bmiHeader.biSize + pBmi->bmiHeader.biClrUsed;

	// create GDI+ object
	Bitmap* pBitmap = new Bitmap(pBmi, pBits);
	if (!pBitmap || (pBitmap->GetLastStatus()!=Ok))
	{
		ASSERT(0);
		delete pBitmap;
		return NULL;
	}
	return pBitmap;
}

///
/// Create a GDI+ bitmap from a packed DIB (a global memory chunk pointing to a
/// BITMAPINFO structure immediately followed by the array of bytes that define
/// the pixels of the bitmap).
/// Note: on 32-bit systems, the HGLOBAL is not quite different from a pointer
///
Bitmap* SCBitmapFromHGLOBAL(HGLOBAL hMem, SCShortDCState& rDCState)
{
	ASSERT(hMem);
	if (!hMem)
		return NULL;

	// get the BITMAPINFO
	BITMAPINFO* pBmi = (BITMAPINFO*)hMem; //GlobalLock(hMem);

	// Locate the bits after the color table:
	// Since the DIB is packed, the biClrUsed member must be either zero or
	// the actual size of the color table
	INT iNbColors = DIBNumColors(LPBITMAPINFOHEADER(pBmi));
	BYTE* pBits = (BYTE*)pBmi + pBmi->bmiHeader.biSize + iNbColors*sizeof(RGBQUAD);

	// create GDI+ object
	Bitmap* pBitmap = NULL;
	if (32==pBmi->bmiHeader.biBitCount)
		pBitmap = new Bitmap(pBmi->bmiHeader.biWidth, pBmi->bmiHeader.biHeight, 4*pBmi->bmiHeader.biWidth,
				PixelFormat32bppARGB, pBits);
	else
	{
		pBitmap = new Bitmap(pBmi, pBits);

		INT iRop2 = rDCState.dwRop2;
		// Update color palette for 1-bpp.
		if (1==pBmi->bmiHeader.biBitCount)
		{
			RGBQUAD* pColors;
			RGBQUAD MonoColors[2];
			if (rDCState.bMonoDC)
			{// Slight difference for DIB? Is it ONLY when the DC IS MONOCHROME that
			 // background and text colors come into play?

			// "When an application selects a two-color DIB pattern brush into a monochrome
			// device context, Windows ignores the colors specified in the DIB and instead
			// displays the pattern brush using the current text and background colors of
			// the device context. Pixels mapped to the first color 
			// (at offset 0 in the DIB color table) of the DIB are displayed using the
			// text color. Pixels mapped to the second color (at offset 1 in the color table)
			// are displayed using the background color."
				pColors = (RGBQUAD*)&MonoColors;
				SCFillMonochromePalette(rDCState, (PPALETTEENTRY)pColors);
			} else
			{// ignore background and text colors, and use the DIB color table
				pColors = (RGBQUAD*)&pBmi->bmiColors;
			}
			#define SC_ISWHITE_RGBQUAD(q) (255==q.rgbRed && 255==q.rgbGreen && 255==q.rgbBlue)

			ColorPalette* pPal = (ColorPalette*)new BYTE[sizeof(ColorPalette) + iNbColors*sizeof(ARGB)];
			pPal->Flags = PaletteFlagsHasAlpha;
			pPal->Count = iNbColors;

			INT iAlpha = 255;
			INT i;
			switch (iRop2)
			{
			case R2_MASKPEN:
				// The normal code is "black=>opaque, and white=>transparent". But we
				// make black pixels half-black and make white pixels transparent.
				// take it as some hand-tuned "gamma corection".
				for (i=0; (i<iNbColors); i++)
				{
					if (SC_ISWHITE_RGBQUAD(pColors[i]))
						iAlpha = 0;	// fully transparent;
					else
						iAlpha = 255; // fully opaque (128 works better; why?)
					pPal->Entries[i] = Color::MakeARGB(iAlpha, pColors[i].rgbRed,
															pColors[i].rgbGreen,
															pColors[i].rgbBlue);
				}
				break;

			default:
				// normal palette
				for (i=0; (i<iNbColors); i++)
				{
					pPal->Entries[i] = Color::MakeARGB(255, pColors[i].rgbRed,
															pColors[i].rgbGreen,
															pColors[i].rgbBlue);
				}
			}
			pBitmap->SetPalette(pPal);
			delete [] pPal;
		}
	}
	//GlobalUnlock(hMem);

	if (pBitmap && (pBitmap->GetLastStatus()!=Ok))
	{
		ASSERT(0);
		delete pBitmap;
		return NULL;
	}
	return pBitmap;
}

///
/// Create a GDI+ bitmap from a handle to a Windows bitmap.
///
Bitmap* SCBitmapFromMemBmp(HBITMAP hBM)
{
	ASSERT(hBM);
	// GDI+ 1.0: we don't have a simple constructor Bitmap::Bitmap(HBITMAP)
	// But a palette residing outside the bitmap was carefully cast in. Jeez!
	Bitmap* pBitmap = new Bitmap(hBM, (HPALETTE)NULL);
	if (pBitmap && (pBitmap->GetLastStatus()!=Ok))
	{
		ASSERT(0);
		delete pBitmap;
		return NULL;
	}
	return pBitmap;
}

///
/// Create a two-color palette to use with the monochrome brush currently selected into a DC.
///	"A brush created by using a monochrome (1 bit per pixel) bitmap has
///	the text and background colors of the device context to which it is drawn.
///	Pixels represented by a 0 bit are drawn with the current text color;
///	pixels represented by a 1 bit are drawn with the current background color."
///
HPALETTE SCCreatePatternPalette(SCShortDCState& rDCState)
{
	// Create the logical palette based on the entries
	// Allocate memory for the palette.
	LPLOGPALETTE lpLogPal = (LPLOGPALETTE)new BYTE [sizeof(LOGPALETTE) + 2*sizeof(PALETTEENTRY)];
	if (!lpLogPal)
		return NULL;
	
	// Initialize.
	lpLogPal->palVersion = 0x300;
	lpLogPal->palNumEntries = 2;
	
	// Update colors in palette.
	SCFillMonochromePalette(rDCState, lpLogPal->palPalEntry);
	
	// Create the palette.
	HPALETTE hPal = CreatePalette(lpLogPal);
	
	// Clean up.
	delete [] (BYTE*)lpLogPal;
	
	return hPal;
}

///
/// Create a two-color bitmap representing a monochrome brush.
///	"A brush created by using a monochrome (1 bit per pixel) bitmap has
///	the text and background colors of the device context to which it is drawn.
///	Pixels represented by a 0 bit are drawn with the current text color;
///	pixels represented by a 1 bit are drawn with the current background color."
///
// Direct method, with external palette
Bitmap* SCPatternFromMemBmp(HBITMAP hBM, SCShortDCState& rDCState)
{
	ASSERT(hBM);
	rDCState.bMonoBrush = FALSE;
#if 0
	// Won't work: GDI+ ignores the palette this time (try to understand)
	HPALETTE hPal = SCCreatePatternPalette(rDCState);
	ASSERT(hPal);
	Bitmap* pBitmap = new Bitmap(hBM, hPal);
	if (!pBitmap)
		return NULL;
	if (pBitmap->GetLastStatus()!=Ok)
	{
		ASSERT(0);
		delete pBitmap;
		pBitmap = NULL;
	}
	DeleteObject(hPal);
#else

	BITMAP bm;
	int iRes = GetObject(hBM, sizeof(BITMAP), &bm);
	ASSERT(iRes);

	// Trying to set a GDI+ palette after bitmap creation
	Bitmap* pBitmap = new Bitmap(hBM, (HPALETTE)NULL);
	if (!pBitmap)
		return NULL;
	if (pBitmap->GetLastStatus()!=Ok)
	{
		ASSERT(0);
		delete pBitmap;
		return NULL;
	}
	if (bm.bmBitsPixel!=1)
		return pBitmap;
	rDCState.bMonoBrush = TRUE;

	// Update color palette for 1-bpp.
	if (!SCSetMonochromeBrushPalette(pBitmap, rDCState))
	{
		ASSERT(0);
		delete pBitmap;
		pBitmap = NULL;
	}
#endif

	return pBitmap;
}


///
/// Create a GDI+ brush from a GDI LOGBRUSH.
///
Brush* SCBrushFromLogBrush(LOGBRUSH& rLogBrush, SCShortDCState& rDCState)
{
	Brush* pBrush = NULL;
	rDCState.bMonoBrush = FALSE;

	switch (rLogBrush.lbStyle)
	{
	case BS_SOLID:
		{// Solid brush
			Color BrushColor;
			BrushColor.SetFromCOLORREF(rLogBrush.lbColor);
			pBrush = new SolidBrush(BrushColor);
		}
		break;
		
	case BS_HATCHED:
		{// Hatched brush
			HatchStyle hatchStyle;
			switch (rLogBrush.lbHatch)
			{
			case HS_BDIAGONAL:
				hatchStyle = HatchStyleBackwardDiagonal;
				break;
			case HS_CROSS:
				hatchStyle = HatchStyleCross;
				break;
			case HS_DIAGCROSS:
				hatchStyle = HatchStyleDiagonalCross;
				break;
			case HS_FDIAGONAL:
				hatchStyle = HatchStyleForwardDiagonal;
				break;
			case HS_HORIZONTAL:
				hatchStyle = HatchStyleHorizontal;
				break;
			case HS_VERTICAL:
				hatchStyle = HatchStyleVertical;
				break;
			default:
				ASSERT(0); // not reached
			}

			Color FgColor;
			FgColor.SetFromCOLORREF(rLogBrush.lbColor);

			// Background color is controlled by current BkColor and BkMode in DC
			COLORREF ColorRef = rDCState.crBkColor;
			BYTE bAlpha = (TRANSPARENT==rDCState.dwBkMode) ? 0 : 255;
			Color BkColor(bAlpha, GetRValue(ColorRef), GetGValue(ColorRef), GetBValue(ColorRef));
			pBrush = new HatchBrush(hatchStyle, FgColor, BkColor);
		}
		break;

	case BS_PATTERN:
	case BS_PATTERN8X8:
		{// Patterned brush (memory bitmap) referenced by a HBITMAP in lbHatch
			//	"A brush created by using a monochrome (1 bit per pixel) bitmap has
			//	the text and background colors of the device context to which it is drawn.
			//	Pixels represented by a 0 bit are drawn with the current text color;
			//	pixels represented by a 1 bit are drawn with the current background color."
			//
			Bitmap* pBitmap = SCPatternFromMemBmp((HBITMAP)rLogBrush.lbHatch, rDCState);

			if (pBitmap)
			{
				pBrush = new TextureBrush(pBitmap);
				delete pBitmap;
			}
		}
		break;

	case BS_DIBPATTERNPT:
		{// Patterned brush (packed DIB) referenced by a pointer in lbHatch
			Bitmap* pBitmap = SCBitmapFromPtr((LPBYTE)rLogBrush.lbHatch);

			if (pBitmap)
			{
				pBrush = new TextureBrush(pBitmap);
				delete pBitmap;
			}
		}
		break;

	case BS_DIBPATTERN:
	case BS_DIBPATTERN8X8:
		{// Patterned brush (packed DIB) referenced by an HGLOBAL in lbHatch
			Bitmap* pBitmap = SCBitmapFromHGLOBAL((HGLOBAL)rLogBrush.lbHatch, rDCState);

			if (pBitmap)
			{
				pBrush = new TextureBrush(pBitmap);
				delete pBitmap;
			}
		}
		break;

	case BS_NULL:
		// pBrush = NULL; // already done
		break;

	case BS_INDEXED:
	case BS_MONOPATTERN:
		// Undocumented (maybe driver specific)
		ASSERT(0);
		break;

	default:
		ASSERT(0);
	}

	ASSERT(!pBrush || (pBrush->GetLastStatus()==Ok));
	return pBrush;
}

///
/// Create a GDI+ brush from a GDI LOGPEN.
///
Pen* SCPenFromLogPen(LOGPEN& rLogPen)
{
	if (PS_NULL==rLogPen.lopnStyle) // no bit masking is required
		return NULL;

	Color PenColor;
	PenColor.SetFromCOLORREF(rLogPen.lopnColor);

	Pen* pPen = new Pen(PenColor, (REAL)rLogPen.lopnWidth.x);
	// Line style
	switch (rLogPen.lopnStyle)
	{
	case PS_SOLID:
		pPen->SetDashStyle(DashStyleSolid);
		break;

	case PS_DASH:
		pPen->SetDashStyle(DashStyleDash);
		break;

	case PS_DOT:
		pPen->SetDashStyle(DashStyleDot);
		break;

	case PS_DASHDOT:
		pPen->SetDashStyle(DashStyleDashDot);
		break;

	case PS_DASHDOTDOT:
		pPen->SetDashStyle(DashStyleDashDotDot);
		break;

	case PS_INSIDEFRAME:
		// The pen is solid, geometric
		pPen->SetDashStyle(DashStyleSolid);

		// GDI:"When this pen is used in any graphics device interface (GDI) drawing
		// function that takes a bounding rectangle, the dimensions of the figure
		// are shrunk so that it fits entirely in the bounding rectangle, taking into
		// account the width of the pen."

		// GDI+:"PenAlignmentInset Specifies, when drawing a polygon,
		// that the pen is aligned on the inside of the edge of the polygon."
		pPen->SetAlignment(PenAlignmentInset);

		// One of the documentations is clearer than the other: make your choice.
		break;

	case PS_ALTERNATE:
		// fall through
	default:
		ASSERT(0);
	}

	// Investigate to find out if a default GDI+ pen should be considered GEOMETRIC.
	// If so apply default join and cap styles
#pragma message( __FILE__  "(449): TODO: Review default GDI+ pen")
#if 0
	// Default values (cf. MSDN "Pens in Win32")
		// Lines joint (applies only to PS_GEOMETRIC pens in GDI)
	pPen->SetLineJoin(LineJoinRound);

		// End cap (applies only to PS_GEOMETRIC pens in GDI)
	pPen->SetLineCap(LineCapRound, LineCapRound, DashCapRound);
#endif

	ASSERT(!pPen || (pPen->GetLastStatus()==Ok));
	return pPen;
}

///
/// Create a GDI+ brush from a GDI EXTLOGPEN.
///
Pen* SCPenFromExtLogPen(EXTLOGPEN* pExtLogPen, SCShortDCState& rDCState)
{
	ASSERT(pExtLogPen);

	INT iPenStyle = pExtLogPen->elpPenStyle & PS_STYLE_MASK;  // style bits masking is required
	if (PS_NULL==iPenStyle)
		return NULL;

	// Note: don't know how to tell GDI+ about PS_COSMETIC or PS_GEOMETRIC pens
	INT iPenType = pExtLogPen->elpPenStyle & PS_TYPE_MASK;

	// Default pen width and color
	INT iWidth = (PS_GEOMETRIC==iPenType) ? pExtLogPen->elpWidth : 1;
	Color PenColor;
	PenColor.SetFromCOLORREF(pExtLogPen->elpColor);

	Pen* pPen = new Pen(PenColor, (REAL)iWidth);

	// Line style
	switch (iPenStyle)
	{
	case PS_SOLID:
		pPen->SetDashStyle(DashStyleSolid);
		break;

	case PS_DASH:
		pPen->SetDashStyle(DashStyleDash);
		break;

	case PS_DOT:
		pPen->SetDashStyle(DashStyleDot);
		break;

	case PS_DASHDOT:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -