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

📄 scgdiutils.cpp

📁 Source code for EMFexplorer 1.0
💻 CPP
📖 第 1 页 / 共 2 页
字号:
/*
*	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 "SCGDIUtils.h"
#include "MSDib.h"
#include "SCGenInclude.h"
#include SC_INC_GENLIB(SCGenMath.h)
#include SC_INC_GENLIB(SCGenDefs.h)
#include <afxext.h> // printdlg

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

///
/// Calculates the palette size in bytes. If the info. block
/// is of the BITMAPCOREHEADER type, the number of colors is
/// multiplied by 3 to give the palette size, otherwise the 
/// number of colors is multiplied by 4.
///
WORD SCColorTableSize (LPBITMAPINFOHEADER lpbih)
{
    if (NEW_DIB_FORMAT(lpbih))
    {
      if (lpbih->biCompression == BI_BITFIELDS)
         /* Remember that 16/32bpp dibs can still have a color table */
         return (sizeof(DWORD) * 3) + (DIBNumColors(lpbih) * sizeof (RGBQUAD));
      else
         return (DIBNumColors(lpbih) * sizeof(RGBQUAD));
    }
    else
      return (DIBNumColors(lpbih) * sizeof(RGBTRIPLE));
}

///
/// Create a 24bpp RGB copy of a palette bitmap.
/// hRefDC must contain the realized palette from where colors are taken.
///
HBITMAP SCConvertPalDIBToRGB(HDC hRefDC, LPCBYTE lpSrcBits, LPCBITMAPINFO lpSrcBmi)
{
	INT iWidth = lpSrcBmi->bmiHeader.biWidth;
	INT iHeight = abs(lpSrcBmi->bmiHeader.biHeight);
    
    BITMAPINFO bmiTarget;
    bmiTarget.bmiHeader.biSize = sizeof( BITMAPINFOHEADER );
    bmiTarget.bmiHeader.biWidth = iWidth;
    bmiTarget.bmiHeader.biHeight = lpSrcBmi->bmiHeader.biHeight;
    bmiTarget.bmiHeader.biPlanes = 1;
    bmiTarget.bmiHeader.biBitCount = 24;
    bmiTarget.bmiHeader.biCompression = BI_RGB;
    bmiTarget.bmiHeader.biSizeImage = 0;
    bmiTarget.bmiHeader.biXPelsPerMeter = 0;
    bmiTarget.bmiHeader.biYPelsPerMeter = 0;
    bmiTarget.bmiHeader.biClrUsed = 0;
    bmiTarget.bmiHeader.biClrImportant = 0;

    VOID* lpTargetBits;
    HBITMAP hTargetBitmap = CreateDIBSection(hRefDC, &bmiTarget, DIB_RGB_COLORS, &lpTargetBits, NULL, 0 );
    HDC hTargetDC = CreateCompatibleDC( hRefDC );
    HBITMAP hOldTargetBitmap = (HBITMAP)SelectObject( hTargetDC, hTargetBitmap );

	INT iRes = SetDIBitsToDevice(hTargetDC, 0, 0, iWidth, iHeight, 0, 0,
			0, iHeight, lpSrcBits, lpSrcBmi, DIB_PAL_COLORS);
	ASSERT(iRes);
	GdiFlush(); // let GDI finish before we access the bits

	// Cleanup
	SelectObject(hTargetDC, hOldTargetBitmap);
	DeleteDC(hTargetDC);

	return hTargetBitmap;
}

void SCNormalizeRect(LPRECT prc)
{
	ASSERT(prc);
	if (prc->right < prc->left)
		SMC_ISWAP(prc->right,  prc->left);
	if (prc->bottom < prc->top)
		SMC_ISWAP(prc->bottom, prc->top);
}

void SCGetNormalizedRect(LPRECT pRcDest, LPCRECT pRcSrc)
{
	ASSERT(pRcDest && pRcSrc);
	if (pRcSrc->right < pRcSrc->left)
	{
		pRcDest->left = pRcSrc->right;
		pRcDest->right = pRcSrc->left;
	} else
	{
		pRcDest->left = pRcSrc->left;
		pRcDest->right = pRcSrc->right;
	}

	if (pRcSrc->bottom < pRcSrc->top)
	{
		pRcDest->top = pRcSrc->bottom;
		pRcDest->bottom = pRcSrc->top;
	} else
	{
		pRcDest->top = pRcSrc->top;
		pRcDest->bottom = pRcSrc->bottom;
	}
}

///
/// Draw a frame and right-bottom shadow
///
void SCDrawFrameAndShadow(CDC *pDC, int x, int y, int cx, int cy, int iShWdt, COLORREF BkColor, BOOL bFrame/*=TRUE*/)
{
	ASSERT(pDC);

	int iXRight  = x + cx;
	int iYBottom = y + cy;

	// Shadow
	if (iShWdt)
	{
		CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(BLACK_BRUSH));
		
		// Right band
		CRect rc(iXRight, y + 2, iXRight + iShWdt + 1, iYBottom + iShWdt + 1);
		pDC->FillRect(&rc, pBrush);
		
		// Bottom band
		rc.left = x + 2;
		rc.top = iYBottom;
		pDC->FillRect(&rc, pBrush);
	}

	// Frame
	if (bFrame)
	{
		CRect rc(x, y, iXRight, iYBottom);
		InflateRect(&rc, 1, 1);
		
		CBrush *pBrush = CBrush::FromHandle((HBRUSH)GetStockObject(NULL_BRUSH));
		CBrush *pOldBrush = pDC->SelectObject(pBrush);
		
		CPen Pen;
		Pen.CreatePen(PS_SOLID, 0, BkColor);
		CPen* pOldPen = pDC->SelectObject(&Pen);
		int iOldRop2 = pDC->SetROP2(R2_NOTCOPYPEN);
		
		pDC->Rectangle(&rc);

		// Clean up
		pDC->SetROP2(iOldRop2);
		pDC->SelectObject(pOldPen);
		pDC->SelectObject(pOldBrush);
		Pen.DeleteObject();
	}
}

///
/// Comptutes character extents by hand (panic function)
///
BOOL SCComputeTextExtentPointW(HDC hAttDC, LPCWSTR pwString, INT iCount, INT *pCharDx, SIZE &TextSize)
{
	ASSERT(pCharDx);
	if (!pCharDx)
		return FALSE;

	pCharDx[0] = 0;
	SIZE tmpSize;

	TextSize.cy = 0;
	for (INT nInd = 0; (nInd < iCount); nInd++)
	{
		GetTextExtentPoint32W(hAttDC, pwString, nInd+1, &tmpSize);
		pCharDx[nInd] = tmpSize.cx;

		if (TextSize.cy<tmpSize.cy)
			TextSize.cy = tmpSize.cy;
	}
	TextSize.cx = tmpSize.cx;

	return TRUE;
}

///
/// Returns an array containing the width of each character in a text.
///	The lpCharWidths buffer must be large enough to hold iCount ints.
///
BOOL SCGetTextCharWidthsW(HDC hDC, LPCWSTR pwString, INT iCount, INT *lpCharWidths)
{
	ASSERT(lpCharWidths);
	if (!lpCharWidths)
		return FALSE;

	// We want the horizontal extents (otherwise, for a vertical font,
	// GetTextExtentExPoint would return character heights in lpCharWidths)
	HFONT hFont = NULL;
	HFONT hHorizFont = NULL;
	if (hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT))
	{
		LOGFONT LogFont;
		::GetObject(hFont, sizeof(LogFont), &LogFont);
		if (LogFont.lfEscapement)
		{
			LogFont.lfEscapement = 0;
			LogFont.lfOrientation = 0;
			hHorizFont = (HFONT)CreateFontIndirect(&LogFont);
			if (hHorizFont)
				SelectObject(hDC, hHorizFont);
		}
	}

	// SetTextJustification(hDC, 0, 0);

	// Compute extents
	SIZE Size;
	INT bRes = GetTextExtentExPointW(hDC, pwString, iCount, 0, NULL, lpCharWidths, &Size);
	// Do not ASSERT: some fonts support characters with 0 width (A+B+C)
	//ASSERT(Size.cx && Size.cy && *lpCharWidths);
	if (0 == bRes)
	{
		DWORD dwGLE = GetLastError();
		// panic
		if (!SCComputeTextExtentPointW(hDC, pwString, iCount, lpCharWidths, Size))
		{
			// panic panic
			if (hHorizFont)
			{
				SelectObject(hDC, hFont);
				DeleteObject(hHorizFont);
			}
			return FALSE;
		}
	}
	
	// Convert extents to char widths
	for (INT i = iCount - 1; i>0; i--)
		lpCharWidths[i] -= lpCharWidths[i-1];

	if (hHorizFont)
	{
		SelectObject(hDC, hFont);
		DeleteObject(hHorizFont);
	}
	return TRUE;
}

BOOL SCGetTextCharWidthsHImW(HDC hDC, LPCWSTR pwString, INT iCount, INT *lpCharWidths, float fScaleX, float fScaleY)
{
	ASSERT(lpCharWidths);
	if (!lpCharWidths)
		return FALSE;

	BOOL bResult = TRUE;

	// We want the horizontal extents (otherwise, for a vertical font,
	// GetTextExtentExPoint would return character heights in lpCharWidths)
	HFONT hFont = NULL;
	HFONT hHorizFont = NULL;
	if (hFont = (HFONT)GetCurrentObject(hDC, OBJ_FONT))
	{
		LOGFONT LogFont;
		::GetObject(hFont, sizeof(LogFont), &LogFont);
		if (LogFont.lfEscapement)
		{
			LogFont.lfEscapement = 0;
			LogFont.lfOrientation = 0;
			hHorizFont = (HFONT)CreateFontIndirect(&LogFont);
			if (hHorizFont)
				SelectObject(hDC, hHorizFont);
		}
	}

	// SetTextJustification(hDC, 0, 0);

	// Compute extents
	SIZE Size;
	INT bRes = GetTextExtentExPointW(hDC, pwString, iCount, 0, NULL, lpCharWidths, &Size);

	ASSERT(Size.cx && Size.cy && *lpCharWidths);
	if (0 == bRes)
	{
		DWORD dwGLE = GetLastError();
		// panic
		bResult = SCComputeTextExtentPointW(hDC, pwString, iCount, lpCharWidths, Size);
	}
	
	// Convert extents to char widths
	if (bResult)
	{
		for (INT i = iCount - 1; i>0; i--)
			lpCharWidths[i] -= lpCharWidths[i-1];

		// text aspect ratio
		float fRatio = (float)(fabs(fScaleY)/fabs(fScaleX));
		for (INT j = 0; j<iCount; j++)
			lpCharWidths[j] = (int)(lpCharWidths[j]*fRatio);
	}

	if (hHorizFont)
	{
		SelectObject(hDC, hFont);
		DeleteObject(hHorizFont);
	}
	return bResult;
}


///
/// Expand a monochrome DIB bitmap to and array of lWidth x lHeight pixels.
/// If lWidth x lHeight is larger than the monochrome bitmap, the latter is replicated.
///
BYTE* SCExpandMask(LONG lWidth, LONG lHeight,
				   LONG lxMask, LONG lyMask,
				   LPCBYTE pBitsMask, LPCBITMAPINFO pBmiMask, DWORD dwUsageMask, BOOL bTopDown/*=FALSE*/)
{
	ASSERT(pBitsMask && pBmiMask);
	ASSERT(dwUsageMask==2/*DIB_PAL_INDICES*/);
	ASSERT(lWidth>0 && lHeight>0);
	ASSERT(1==pBmiMask->bmiHeader.biBitCount && 1==pBmiMask->bmiHeader.biPlanes);
	ASSERT(pBmiMask->bmiHeader.biHeight>0);

	BYTE* pResult = new BYTE[lWidth*lHeight];
	BYTE* pDest = pResult;

	// Note: the mask is always a 1-bit DIB. And:
	// "1-bit DIBs are stored using each bit as an index into the color table.
	// The most significant bit is the leftmost pixel."
	DWORD dwBytesPerLine = WIDTHBYTES(pBmiMask->bmiHeader.biWidth);
	DWORD dwStartScan = lyMask * dwBytesPerLine;
	// Theoretical first useful bit inside the first useful byte on scanline
	BYTE bStartBitNumber = (BYTE)(lxMask % 8);
	// Theoretical max useful bit inside the last useful byte on scanline
	BYTE bMaxBitNumber = (BYTE)(pBmiMask->bmiHeader.biWidth % 8);
	DWORD dwMaxByteOnLine = pBmiMask->bmiHeader.biWidth >> 3;
	
	BYTE* pXStart = (BYTE*)pBitsMask + dwStartScan;
	BYTE* pYLimit = (BYTE*)pBitsMask + (pBmiMask->bmiHeader.biHeight-1) * dwBytesPerLine;

	if (bTopDown)
	{// Make the layout for a top-down bitmap
		for (LONG y=0; (y<lHeight); y++)
		{
			BYTE* pXLimit = pXStart + dwMaxByteOnLine;	 // inclusive end of scanline
			BYTE* pX = pXStart + (lxMask >> 3);			 // byte on the scanline
			BYTE bBitNumber = bStartBitNumber;			 // theoretical bit inside the byte
			for (LONG x=0; (x<lWidth); x++, pDest++)
			{
				// the most significant bit is the leftmost pixel; so get the complement
				// of the theoretical bit number
				if (*pX & (1<<(7 - bBitNumber)))
					*pDest = 1;
				else
					*pDest = 0;
				
				bBitNumber++;
				if (pX==pXLimit)
				{// last useful bit on last useful byte reached: restart
					if (bBitNumber>=bMaxBitNumber)
					{
						pX = pXStart + (lxMask >> 3);
						bBitNumber = bStartBitNumber;
					}
				} else
				if (bBitNumber>7)
				{// no more bits available in this byte: go to next byte
					++pX;
					if (pX>pXLimit)
					{// can't go next: back to start
						pX = pXStart + (lxMask >> 3);
						bBitNumber = bStartBitNumber;
					} else
						bBitNumber = 0; // first bit of next byte
				}
			}
			// next scan
			pXStart += dwBytesPerLine;
			if (pXStart>pYLimit)
			{// restart to begining of mask
				pXStart = (BYTE*)pBitsMask + dwStartScan;
			}
		}
	} else
	{// Make the layout for a bottom-up bitmap.
		BYTE* pDestRow = pResult + lWidth*lHeight;
		for (LONG y=0; (y<lHeight); y++)
		{
			BYTE* pXLimit = pXStart + dwMaxByteOnLine;		// inclusive end of scanline
			BYTE* pX = pXStart + (lxMask >> 3);				// byte on the scanline
			BYTE bBitNumber = bStartBitNumber;				// theoretical bit inside the byte
			
			pDestRow -= lWidth;
			pDest = pDestRow;
			
			for (LONG x=0; (x<lWidth); x++, pDest++)
			{
				// the most significant bit is the leftmost pixel; so get the complement
				// of the theoretical bit number
				if (*pX & (1<<(7 - bBitNumber)))
					*pDest = 1;
				else
					*pDest = 0;
				
				bBitNumber++;

⌨️ 快捷键说明

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