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

📄 scgdiplusutils.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 4 页
字号:
			}
		}
	}
	pIGraphics->SCReleaseDC(hOutputDC);

		// Ensure that the brush is in destination dc
	HBRUSH hBrush = NULL;
	HBRUSH hOldBrush = NULL;
	Brush* pBrush = pIGraphics->SCGetBrush(); // brush of destination
	if (pBrush)
	{
		Color BrushColor;
		switch(pBrush->GetType())
		{
		case BrushTypeSolidColor:
			((SolidBrush*)pBrush)->GetColor(&BrushColor);
			hBrush = CreateSolidBrush(BrushColor.ToCOLORREF());
			break;

		case BrushTypeHatchFill:
			((HatchBrush*)pBrush)->GetBackgroundColor(&BrushColor);
			hBrush = CreateSolidBrush(BrushColor.ToCOLORREF());
			break;
		}
	} // else NULL brush, let default brush in place.
	  // TODO: check that the ROP doesn't use the brush
	if (hBrush)
		hOldBrush = (HBRUSH)SelectObject(hDestDC, hBrush);

		// Merge source and dest (this is not smoothed)
	StretchDIBits(hDestDC, 0, 0, iTmpWidth, iTmpHeight,
					XSrc, YSrc, nSrcWidth, nSrcHeight,
					lpBits, lpBitsInfo, iUsage, dwRop);

		// We are done with dest DC
	if (hBrush)
	{
		SelectObject(hDestDC, hOldBrush);
		DeleteObject(hBrush);
	}
	SelectObject(hDestDC, hOldBmp);
	DeleteDC(hDestDC);

	// Create GDI+ bitmap
	{
		Bitmap Bmp(hDestBmp, (HPALETTE)NULL);
		ASSERT(Bmp.GetLastStatus()==Ok);
		
		// GDI+ drawing (smoothed a little according to graphics settings)
		Rect destRect(XDest, YDest, nDestWidth, nDestHeight);
		pIGraphics->SCDrawBitmap(&Bmp, destRect);
	}

	// Clean up
	DeleteObject(hDestBmp);

	return TRUE;
}

///
/// Compute a normalized rectangle to use in GDI+ functions.
/// (GDI's twisted rectangles would result in negative width/height, confusing GDI+)
///
void SCNormalizedRectFromRECT(Rect* pRect, LPCRECT pRc)
{
	ASSERT(pRect && pRc);
	if (pRc->right < pRc->left)
	{
		pRect->X = pRc->right;
		pRect->Width = pRc->left - pRc->right;
	} else
	{
		pRect->X = pRc->left;
		pRect->Width = pRc->right - pRc->left;
	}

	if (pRc->bottom < pRc->top)
	{
		pRect->Y = pRc->bottom;
		pRect->Height = pRc->top - pRc->bottom;
	} else
	{
		pRect->Y = pRc->top;
		pRect->Height = pRc->bottom - pRc->top;
	}
}

///
/// Compute clockwise angles to use in GDI+ functions from GDI's basic information.
///
void SCBuildArcAngles(LPCRECTL pBox, LPCPOINTL pPtStart, LPCPOINTL pPtEnd, INT iArcDir,
					  double& dStartAngle, double& dSweepAngle)
{
	double dCenterX = (pBox->right + pBox->left)/2;
	double dCenterY = (pBox->bottom + pBox->top)/2;
	
	dStartAngle = SC_DEGREES(atan2((pPtStart->y - dCenterY), pPtStart->x - dCenterX));
	double dEndAngle = SC_DEGREES(atan2((pPtEnd->y - dCenterY), pPtEnd->x - dCenterX));
	dSweepAngle = (dEndAngle - dStartAngle);

	// arc direction is used (AD_COUNTERCLOCKWISE or AD_CLOCKWISE)
	if (iArcDir==AD_CLOCKWISE)
	{// AD_CLOCKWISE for GDI
		if (dSweepAngle<=0)
		{// Negative values are counterclockwise for GDI+. So get the angle's negative complement.
			dSweepAngle = -(360 + dSweepAngle); // counterclockwise for GDI+
		} // else clockwise for GDI+
	} else
	{// AD_COUNTERCLOCKWISE for GDI
		if (dSweepAngle>=0)
		{// Positive values are clockwise for GDI+. So get the angle's negative complement.
			dSweepAngle = -(360 - dSweepAngle); // counterclockwise for GDI+
		} // else clockwise for GDI+
	}
}

///
/// Intersection of a cercle define by its center and radius, and a line passing by this center.
///	(Angle is in degrees)
///
void SCIntersectLineAndCircle(Point& PtRes, POINTL* pPtCenter, DWORD dwRadius, double fLineAngle)
{
	double dAngle = -SC_RAD(fLineAngle);
	PtRes.X = static_cast<INT>(pPtCenter->x + dwRadius*cos(dAngle));
	PtRes.Y = static_cast<INT>(pPtCenter->y + dwRadius*sin(dAngle));
}

///
/// Intersection of an ellipse define by a rectangle, and a line passing by its center.
/// (Angle is in degrees)
///
void SCIntersectLineAndEllipse(Point& PtRes, LPCRECTL pBox, double fLineAngle)
{
	int xPtCenter = (pBox->left + pBox->right)/2;
	int yPtCenter = (pBox->top + pBox->bottom)/2;

	double a = (pBox->right - pBox->left);
	double b = (pBox->bottom - pBox->top);

	double dAngle = -SC_RAD(fLineAngle);
	double a_sinAngle = a*sin(dAngle);
	double b_cosAngle = b*cos(dAngle);

	double d = sqrt(a_sinAngle*a_sinAngle + b_cosAngle*b_cosAngle);
	PtRes.X = static_cast<INT>(xPtCenter + (a*b_cosAngle/d));
	PtRes.Y = static_cast<INT>(yPtCenter + (b*a_sinAngle/d));
}

HBRUSH SCBrushFromGdipImage(Image* pImage)
{
	ASSERT(pImage);
	ASSERT(pImage->GetType()==ImageTypeBitmap);

	int iWidth = pImage->GetWidth();
	int iHeight = pImage->GetHeight();
	HDC hdc = CreateCompatibleDC(NULL);
	HBITMAP hbmp = NULL;

	BitmapData BmData;
	Rect rect(0, 0, iWidth, iHeight);
	Status iRes = ((Bitmap*)pImage)->LockBits(&rect, ImageLockModeRead,
		PixelFormat32bppARGB, &BmData);
	ASSERT(iRes==Ok);
	if (iRes==Ok)
	{
		BITMAPINFOHEADER bmih;
		bmih.biSize = sizeof(BITMAPINFOHEADER);
		bmih.biWidth = iWidth;
		bmih.biHeight = iHeight; // bottom-up (beware of sign)
		bmih.biPlanes = 1;
		bmih.biBitCount = 32;
		bmih.biCompression = BI_RGB;
		bmih.biClrUsed = 0;
		// just set the rest to 0
		bmih.biSizeImage = 0;
		bmih.biXPelsPerMeter = 0; 
		bmih.biYPelsPerMeter = 0;
		bmih.biClrImportant = 0;
		bmih.biSizeImage = iWidth * iHeight * 4;
		LPVOID pBits;
		hbmp = CreateDIBSection(hdc, (BITMAPINFO*)&bmih, DIB_RGB_COLORS, &pBits, NULL, 0);
		ASSERT(hbmp);
		if (hbmp)
		{
			SetDIBits(hdc, hbmp, 0, iHeight, (CONST VOID *)BmData.Scan0, (BITMAPINFO*)&bmih, DIB_RGB_COLORS);
		}
	}
	((Bitmap*)pImage)->UnlockBits(&BmData); 

	// Warning: May create resource leak, as we don't call DeleteObject on hbmp
	HBRUSH hBrush = CreatePatternBrush(hbmp);

	DeleteDC(hdc);
	return hBrush;
}

///
/// Perfom a pattern blt opeartion using ROP.
///
INT SCMergeAreaWithPattern(
  I_SCDCGraphics* pIGraphics,    // pointer to destination graphics context
  Rect& destRect,		  // dest. rectangle
  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);
	INT nDestWidth = destRect.Width; // width of destination rectangle
	INT nDestHeight = destRect.Height; // height of destination rectangle
	HBITMAP hDestBmp = CreateCompatibleBitmap(hOutputDC, nDestWidth, nDestHeight);
	ASSERT(hDestBmp);
	if (!hDestBmp)
	{
		DWORD dwError = GetLastError();
		return FALSE;
	}
	HBITMAP hOldBmp = (HBITMAP)SelectObject(hDestDC, hDestBmp);

		// Copy the destination rectangle
	if (!StretchBlt(hDestDC, 0, 0, nDestWidth, nDestHeight,
		   hOutputDC, destRect.X, destRect.Y, nDestWidth, nDestHeight, SRCCOPY))
	{// Maybe failure for rotation/shear found in hOutputDC
	 // (do a manual copy of the destination rectangle)
		int ys = destRect.Y;
		for (int y=0; (y<nDestHeight); y++, ys++)
		{
			int xs = destRect.X;
			for (int x=0; (x<nDestWidth); x++, xs++)
			{
				COLORREF Color = GetPixel(hOutputDC, xs, ys);
				SetPixel(hDestDC, x, y, Color);
			}
		}
	}
	pIGraphics->SCReleaseDC(hOutputDC);

		// Ensure that the brush is in destination dc
	HBRUSH hBrush = NULL;
	Brush* pBrush = pIGraphics->SCGetBrush(); // brush of destination
	if (pBrush)
	{
		Color BrushColor;
		switch(pBrush->GetType())
		{
		case BrushTypeSolidColor:
			((SolidBrush*)pBrush)->GetColor(&BrushColor);
			hBrush = CreateSolidBrush(BrushColor.ToCOLORREF());
			break;

		case BrushTypeHatchFill:
			((HatchBrush*)pBrush)->GetBackgroundColor(&BrushColor);
			hBrush = CreateSolidBrush(BrushColor.ToCOLORREF());
			break;

		case BrushTypeTextureFill:
			{
				Image* pImage = ((TextureBrush*)pBrush)->GetImage();
				ASSERT(pImage);
				hBrush = SCBrushFromGdipImage(pImage);
				delete pImage;
			}
			break;

		default:
			ASSERT(0); // TODO

		}
	} // else NULL brush, let default brush in place.
		// TODO: check that the ROP doesn't use the brush

	// Merge source and dest (this is not smoothed)
	if (hBrush)
	{
		HBRUSH hOldBrush = (HBRUSH)SelectObject(hDestDC, hBrush);
		
		PatBlt(hDestDC, 0, 0, nDestWidth, nDestHeight, dwRop); 
		
		SelectObject(hDestDC, hOldBrush);
		DeleteObject(hBrush);
	} else
	{
		PatBlt(hDestDC, 0, 0, nDestWidth, nDestHeight, dwRop);
	}

	// We are done with dest DC
	SelectObject(hDestDC, hOldBmp);
	DeleteDC(hDestDC);

	// Create GDI+ bitmap
	{
		Bitmap Bmp(hDestBmp, (HPALETTE)NULL);
		ASSERT(Bmp.GetLastStatus()==Ok);
		
		pIGraphics->SCDrawBitmap(&Bmp, destRect);
	}

	// Clean up
	DeleteObject(hDestBmp);

	return TRUE;
}


///////////////////////////////////////////////////////////////////////////////////////////
// The algorithm of this function was adapted from XPDF
// (Patrick Moreau, Martin P.J. Zinser, (c) Glyph & Cog, LLC)
//
// "kludge for polygon fills:  First, it divides up the [subpolys] into
// non-overlapping polygons by simply comparing bounding rectangles.
// Then it connects [subpolys] within a single compound polygon to a single
// point so that [GDI+] can fill the polygon (sort of)."
//
Point* SCConvertPolyPoly(Point* pPolyPoints, DWORD& numPoints,
					  DWORD* pPolyVertices, DWORD& dwNbPolys)
{
	Point* pPoints = pPolyPoints;

	// allocate new points
	int size = numPoints + dwNbPolys*2; // add 2 more points by poly
	Point* pPolyPts = new Point[size];

	// allocate bounding rectangles array
	RECT *rects = new RECT[dwNbPolys];
	
	// rebuild each subpoly
	numPoints = 0;
	Point Pt0(0, 0);
	Point* pLimit = pPoints;
	for (int iPoly = 0; (iPoly < (int)dwNbPolys); ++iPoly)
	{
		// add the points
		int iFirstPt = numPoints;
		pLimit += pPolyVertices[iPoly];
		for (; (pPoints < pLimit); pPoints++)
		{	pPolyPts[numPoints++] = *pPoints; }
		
		// construct bounding rectangle
		rects[iPoly].left = rects[iPoly].right = pPolyPts[iFirstPt].X;
		rects[iPoly].top = rects[iPoly].bottom = pPolyPts[iFirstPt].Y;
		for (int k = iFirstPt + 1; (k < (int)numPoints); ++k)
		{
			if (pPolyPts[k].X < rects[iPoly].left)
				rects[iPoly].left = pPolyPts[k].X;
			else if (pPolyPts[k].X > rects[iPoly].right)
				rects[iPoly].right = pPolyPts[k].X;
			if (pPolyPts[k].Y < rects[iPoly].top)
				rects[iPoly].top = pPolyPts[k].Y;
			else if (pPolyPts[k].Y > rects[iPoly].bottom)
				rects[iPoly].bottom = pPolyPts[k].Y;
		}
		
		// close subpoly if necessary
		if (pPolyPts[numPoints-1].X != pPolyPts[iFirstPt].X ||
			pPolyPts[numPoints-1].Y != pPolyPts[iFirstPt].Y)
		{
			// add point
			pPolyPts[numPoints++] = pPolyPts[iFirstPt];
		}
		
		// length of this subpoly
		pPolyVertices[iPoly] = numPoints - iFirstPt;
		
		// leave an extra point for compound fill hack
		pPolyPts[numPoints++] = Pt0;
	}
	
	// combine compound polygons
	RECT rect;				// temp rect for overlaps detection
	DWORD dwNewNbPolys = 0; // new polygons counter
	int iCurPoly = 0;		// index of current polygon to examine or merge
	int iOverlap = 0;		// index of a polygon overlapping iCurPoly
	int iFirstPt = 0;		// index of first point in iCurPoly
	int iLastPt = 0;		// index of last point in iCurPoly
	while (iCurPoly < (int)dwNbPolys)
	{
		// start a new polygon with the iCurPoly subpoly
		rect = rects[iCurPoly];
		pPolyVertices[dwNewNbPolys] = pPolyVertices[iCurPoly];
		iFirstPt = iLastPt;
		iLastPt += pPolyVertices[iCurPoly] + 1; // +1 for the extra point
		pPolyPts[iLastPt - 1] = pPolyPts[iFirstPt];
		
		// combine overlapping polygons
		++iCurPoly;
		do
		{
			// look for the first subsequent subpoly, if any, which overlaps
			for (iOverlap = iCurPoly; (iOverlap < (int)dwNbPolys); ++iOverlap)
			{
				if (rects[iOverlap].right > rects[iCurPoly].left &&
					rects[iOverlap].left < rects[iCurPoly].right &&
					rects[iOverlap].bottom > rects[iCurPoly].top &&
					rects[iOverlap].top < rects[iCurPoly].bottom)
				{
					// there is an overlap, combine the polygons
					// (by anchoring them at the first point of current polygon)
					for (; (iCurPoly <= iOverlap); ++iCurPoly)
					{
						if (rects[iCurPoly].left < rect.left)
							rect.left = rects[dwNewNbPolys].left;
						if (rects[iCurPoly].right > rect.right)
							rect.right = rects[dwNewNbPolys].right;
						if (rects[iCurPoly].top < rect.top)
							rect.top = rects[dwNewNbPolys].top;
						if (rects[iCurPoly].bottom > rect.bottom)
							rect.bottom = rects[dwNewNbPolys].bottom;
						
						// merge points
						pPolyVertices[dwNewNbPolys] += pPolyVertices[iCurPoly] + 1;
						// anchor this subpoly
						iLastPt += pPolyVertices[iCurPoly] + 1;
						pPolyPts[iLastPt - 1] = pPolyPts[iFirstPt];
					}

					// exit to check next overlap with this compound polygon
					break;
				}
			}
		} while (iOverlap < (int)dwNbPolys && iCurPoly < (int)dwNbPolys);
		
		++dwNewNbPolys;
	}
	
	// free bounding rectangles
	delete [] rects;
	dwNbPolys = dwNewNbPolys;

	return pPolyPts;
}
//////////////////////////////////////////////////////////////////////////////////////////


///
/// Create a GDI+ list of PathPointTypes from a list of GDI point types.
///
BYTE* SCPathPointTypesFROMCurveTypes(LPCBYTE pGDITypes, DWORD dwCount)
{
	ASSERT(pGDITypes);

	BYTE *pTypes = new BYTE[dwCount];

	if (pTypes)
	{
		memmove(pTypes, pGDITypes, dwCount);
		SCConvertGDIPointTypes(pTypes, dwCount);
	}
	return pTypes;
}
	
///
/// Convert (in place) a list of GDI point types to GDI+ PathPointTypes.
///
void SCConvertGDIPointTypes(LPBYTE pTypes, DWORD dwCount)
{
	ASSERT(pTypes);

	// convert path point types
	for (DWORD i=0; (i<dwCount); i++)
	{
		// GDI+ documentation states:
		// "The PathPointType enumeration indicates point types and flags for the data points
		// in a path. Bits 0 through 2 indicate the type of a point, and bits 3 through 7
		// hold a set of flags that specify attributes of a point."
		// Hence the dirty cast of an enum into BYTE;
		// Note that no function takes an array of PathPointType in the GraphicsPath class.
		
		switch (pTypes[i] & SC_PATH_PTMASK)
		{
		case PT_MOVETO:
			pTypes[i] = (BYTE)PathPointTypeStart;
			break;
			
		case PT_LINETO:
			if (pTypes[i] & SC_PATH_CLOSEFIG)
				pTypes[i] = (BYTE)(PathPointTypeLine|PathPointTypeCloseSubpath);
			else
				pTypes[i] = (BYTE)PathPointTypeLine;
			break;
			
		case PT_BEZIERTO:
			if (pTypes[i] & SC_PATH_CLOSEFIG)
				pTypes[i] = (BYTE)(PathPointTypeBezier|PathPointTypeCloseSubpath);
			else
				pTypes[i] = (BYTE)PathPointTypeBezier;
			break;
		}
	}
}

///
/// Subtype of an EMF: EmfTypeEmfOnly|EmfTypeEmfPlusOnly|EmfTypeEmfPlusDual
///
EmfType SCGdipGetEMFType(HENHMETAFILE hemf)
{
	Metafile metafile(hemf);
	MetafileHeader header;
	metafile.GetMetafileHeader(&header);
	switch(header.GetType())
	{
    case MetafileTypeEmfPlusOnly:
		return EmfTypeEmfPlusOnly;

    case MetafileTypeEmfPlusDual:
		return EmfTypeEmfPlusDual;
	}

	return EmfTypeEmfOnly;
}

⌨️ 快捷键说明

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