📄 scgdiutils.cpp
字号:
/*
* 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 + -