导航:[首页]->[wtl]->[Windows 图片处理的部分工具函数]
/*
* resutil.h
*
* Created on: 2012-5-16
* Author: king
*/
#ifndef RESUTIL_H_
#define RESUTIL_H_
#include <atlimage.h>
#include <atlgdi.h>
#include <atlmisc.h>
#pragma comment(lib, "gdiplus.lib")
// 初始化
Gdiplus::Status InitUtil(ULONG_PTR* gdiplusToken);
void FiniUtil(ULONG_PTR gdiplusToken);
/////////////////////////////////////////////////////
// 从文件中读取图片
// 支持BMP, GIF, JPEG, PNG, and TIFF.
bool File2CImage(CImage* img,const TCHAR* path);
// 平整alpha通道失效的问题
void ImplAlpha(CImage* img);
inline bool File2CImageAndImplAlpha(CImage* img,const TCHAR* path){
if(File2CImage(img,path)){
ImplAlpha(img);
return true;
}else{
return false;
}
}
// 支持bmp
bool File2CBitmap(CBitmap* img,const TCHAR* path);
// 支持BMP, GIF, JPEG, PNG, TIFF, and EMF.
bool File2GdiplusImage(Gdiplus::Image** img,const TCHAR* path);
//end
/////////////////////////////////////////////////////
// 平铺图片
void TileBitBlt(
CDCHandle & pDC,
CBitmap & bitmap,
const CRect & rect);
void TileTransparentBlt(
CDCHandle & pDC,
CBitmap & bitmap,
const CRect & rect,
COLORREF crTransparent);
//end
// 图片到rgn
HRGN BitmapToRegion (
HBITMAP hBmp,
COLORREF cTransparentColor = 0,
COLORREF cTolerance = 0x101010);
#endif /* RESUTIL_H_ */
/*
* resutil.cpp
*
* Created on: 2012-5-16
* Author: king
*/
#include "resutil.h"
// http://msdn.microsoft.com/en-us/library/ms534077(v=vs.85).aspx
Gdiplus::Status InitUtil(ULONG_PTR* gdiplusToken){
ATLASSERT(gdiplusToken);
Gdiplus::GdiplusStartupInput gdiplusStartupInput;
return Gdiplus::GdiplusStartup(gdiplusToken, &gdiplusStartupInput, NULL);
}
void FiniUtil(ULONG_PTR gdiplusToken){
Gdiplus::GdiplusShutdown(gdiplusToken);
}
// http://msdn.microsoft.com/en-us/library/tf4bytf8.aspx
bool File2CImage(CImage* img,const TCHAR* path){
ATLASSERT(img);
ATLASSERT(path);
if(!img->IsNull()){
ATLASSERT(0);
img->Destroy();
}
return S_OK == img->Load(path);
}
// 平整alpha通道失效的问题
void ImplAlpha(CImage* img){
ATLASSERT(img);
CSize size_(img->GetWidth(),img->GetHeight());
//处理CImage不能透明问题;
unsigned char* pColor;
for(int i = 0;i < size_.cx; i++)
{
for(int j = 0; j < size_.cy; j++)
{
pColor = (unsigned char *) img->GetPixelAddress(i,j);
if(pColor[3] < 0xFF){
pColor[0] = pColor[0] * pColor[3]/0xFF;
pColor[1] = pColor[1] * pColor[3]/0xFF;
pColor[2] = pColor[2] * pColor[3]/0xFF;
}
}
}
}
bool File2CBitmap(CBitmap* img,const TCHAR* path){
ATLASSERT(img);
ATLASSERT(path);
HBITMAP pbitmap_ = (HBITMAP) LoadImage(
NULL,
path,
IMAGE_BITMAP,
0,
0,
LR_CREATEDIBSECTION | LR_LOADFROMFILE);
if (pbitmap_ == NULL)
return false;
img->Attach(pbitmap_);
return true;
}
// http://msdn.microsoft.com/en-us/library/ms535370(v=vs.85).aspx
bool File2GdiplusImage(Gdiplus::Image** img,const TCHAR* path){
ATLASSERT(img);
ATLASSERT(path);
*img = Gdiplus::Image::FromFile(path);
if(!(*img))
return false;
return Gdiplus::Ok == (*img)->GetLastStatus();
}
///////////////////////////////////////////////////////////////
typedef BOOL (*BltTemp)(
CDCHandle & ,
int, int, int, int,
HDC,
int, int,
COLORREF);
inline BOOL TransparentBltImp(
CDCHandle & pDC,
int x, int y, int nWidth, int nHeight,
HDC hSrcDC,
int xSrc, int ySrc,
COLORREF crTransparent){
return pDC.TransparentBlt(
x,y,nWidth,nHeight,
hSrcDC,
xSrc,ySrc,nWidth,nHeight,
crTransparent);
}
inline BOOL BitBltImp(
CDCHandle & pDC,
int x, int y, int nWidth, int nHeight,
HDC hSrcDC,
int xSrc, int ySrc,
COLORREF){
return pDC.BitBlt(x,y,nWidth,nHeight,hSrcDC,xSrc,ySrc,SRCCOPY);
}
template<BltTemp Func>
void TileBitmapT(
CDCHandle & pDC,
CBitmap & bitmap,
const CRect & rect,
COLORREF colorMask)
{
CSize imgSize_;
bitmap.GetSize(imgSize_);
CDC dcMem;
dcMem.CreateCompatibleDC ( pDC );
dcMem.SelectBitmap(bitmap);
LONG top_ = rect.top,height_;
while(top_ < rect.bottom) {
height_ = imgSize_.cy;
if( top_ + height_ > rect.bottom ) {
height_ = rect.bottom - top_;
}
LONG width_;
LONG left_ = rect.left;
int right_ = rect.right;
while( left_ < right_) {
width_ = imgSize_.cx;
if( left_ + width_ > right_ ) {
width_ = right_ - left_;
}
Func(pDC,left_,top_,width_,height_,dcMem, 0, 0,colorMask);
left_ += width_;
}
top_ += height_;
}
}
void TileBitBlt(
CDCHandle & pDC,
CBitmap & bitmap,
const CRect & rect)
{
TileBitmapT<BitBltImp>(pDC,bitmap,rect,0);
}
void TileTransparentBlt(
CDCHandle & pDC,
CBitmap & bitmap,
const CRect & rect,
COLORREF crTransparent){
TileBitmapT<TransparentBltImp>(pDC,bitmap,rect,crTransparent);
}
// http://www.codeguru.com/cpp/g-m/bitmap/usingregions/article.php/c1751/Converting-a-bitmap-to-a-region.htm
//
// BitmapToRegion : Create a region from the "non-transparent" pixels of a bitmap
// Author : Jean-Edouard Lachand-Robert (http://www.geocities.com/Paris/LeftBank/1160/resume.htm), June 1998.
//
// hBmp : Source bitmap
// cTransparentColor : Color base for the "transparent" pixels (default is black)
// cTolerance : Color tolerance for the "transparent" pixels.
//
// A pixel is assumed to be transparent if the value of each of its 3 components (blue, green and red) is
// greater or equal to the corresponding value in cTransparentColor and is lower or equal to the
// corresponding value in cTransparentColor + cTolerance.
//
HRGN BitmapToRegion (HBITMAP hBmp, COLORREF cTransparentColor, COLORREF cTolerance)
{
HRGN hRgn = NULL;
if (hBmp)
{
// Create a memory DC inside which we will scan the bitmap content
HDC hMemDC = CreateCompatibleDC(NULL);
if (hMemDC)
{
// Get bitmap size
BITMAP bm;
GetObject(hBmp, sizeof(bm), &bm);
// Create a 32 bits depth bitmap and select it into the memory DC
BITMAPINFOHEADER RGB32BITSBITMAPINFO = {
sizeof(BITMAPINFOHEADER), // biSize
bm.bmWidth, // biWidth;
bm.bmHeight, // biHeight;
1, // biPlanes;
32, // biBitCount
BI_RGB, // biCompression;
0, // biSizeImage;
0, // biXPelsPerMeter;
0, // biYPelsPerMeter;
0, // biClrUsed;
0 // biClrImportant;
};
VOID * pbits32;
HBITMAP hbm32 = CreateDIBSection(hMemDC, (BITMAPINFO *)&RGB32BITSBITMAPINFO, DIB_RGB_COLORS, &pbits32, NULL, 0);
if (hbm32)
{
HBITMAP holdBmp = (HBITMAP)SelectObject(hMemDC, hbm32);
// Create a DC just to copy the bitmap into the memory DC
HDC hDC = CreateCompatibleDC(hMemDC);
if (hDC)
{
// Get how many bytes per row we have for the bitmap bits (rounded up to 32 bits)
BITMAP bm32;
GetObject(hbm32, sizeof(bm32), &bm32);
while (bm32.bmWidthBytes % 4)
bm32.bmWidthBytes++;
// Copy the bitmap into the memory DC
HBITMAP holdBmp = (HBITMAP)SelectObject(hDC, hBmp);
BitBlt(hMemDC, 0, 0, bm.bmWidth, bm.bmHeight, hDC, 0, 0, SRCCOPY);
// For better performances, we will use the ExtCreateRegion() function to create the
// region. This function take a RGNDATA structure on entry. We will add rectangles by
// amount of ALLOC_UNIT number in this structure.
#define ALLOC_UNIT 100
DWORD maxRects = ALLOC_UNIT;
HANDLE hData = GlobalAlloc(GMEM_MOVEABLE, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects));
RGNDATA *pData = (RGNDATA *)GlobalLock(hData);
pData->rdh.dwSize = sizeof(RGNDATAHEADER);
pData->rdh.iType = RDH_RECTANGLES;
pData->rdh.nCount = pData->rdh.nRgnSize = 0;
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
// Keep on hand highest and lowest values for the "transparent" pixels
BYTE lr = GetRValue(cTransparentColor);
BYTE lg = GetGValue(cTransparentColor);
BYTE lb = GetBValue(cTransparentColor);
BYTE hr = min(0xff, lr + GetRValue(cTolerance));
BYTE hg = min(0xff, lg + GetGValue(cTolerance));
BYTE hb = min(0xff, lb + GetBValue(cTolerance));
// Scan each bitmap row from bottom to top (the bitmap is inverted vertically)
BYTE *p32 = (BYTE *)bm32.bmBits + (bm32.bmHeight - 1) * bm32.bmWidthBytes;
for (int y = 0; y < bm.bmHeight; y++)
{
// Scan each bitmap pixel from left to right
for (int x = 0; x < bm.bmWidth; x++)
{
// Search for a continuous range of "non transparent pixels"
int x0 = x;
LONG *p = (LONG *)p32 + x;
while (x < bm.bmWidth)
{
BYTE b = GetRValue(*p);
if (b >= lr && b <= hr)
{
b = GetGValue(*p);
if (b >= lg && b <= hg)
{
b = GetBValue(*p);
if (b >= lb && b <= hb)
// This pixel is "transparent"
break;
}
}
p++;
x++;
}
if (x > x0)
{
// Add the pixels (x0, y) to (x, y+1) as a new rectangle in the region
if (pData->rdh.nCount >= maxRects)
{
GlobalUnlock(hData);
maxRects += ALLOC_UNIT;
hData = GlobalReAlloc(hData, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), GMEM_MOVEABLE);
pData = (RGNDATA *)GlobalLock(hData);
}
RECT *pr = (RECT *)&pData->Buffer;
SetRect(&pr[pData->rdh.nCount], x0, y, x, y+1);
if (x0 < pData->rdh.rcBound.left)
pData->rdh.rcBound.left = x0;
if (y < pData->rdh.rcBound.top)
pData->rdh.rcBound.top = y;
if (x > pData->rdh.rcBound.right)
pData->rdh.rcBound.right = x;
if (y+1 > pData->rdh.rcBound.bottom)
pData->rdh.rcBound.bottom = y+1;
pData->rdh.nCount++;
// On Windows98, ExtCreateRegion() may fail if the number of rectangles is too
// large (ie: > 4000). Therefore, we have to create the region by multiple steps.
if (pData->rdh.nCount == 2000)
{
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
if (hRgn)
{
CombineRgn(hRgn, hRgn, h, RGN_OR);
DeleteObject(h);
}
else
hRgn = h;
pData->rdh.nCount = 0;
SetRect(&pData->rdh.rcBound, MAXLONG, MAXLONG, 0, 0);
}
}
}
// Go to next row (remember, the bitmap is inverted vertically)
p32 -= bm32.bmWidthBytes;
}
// Create or extend the region with the remaining rectangles
HRGN h = ExtCreateRegion(NULL, sizeof(RGNDATAHEADER) + (sizeof(RECT) * maxRects), pData);
if (hRgn)
{
CombineRgn(hRgn, hRgn, h, RGN_OR);
DeleteObject(h);
}
else
hRgn = h;
// Clean up
SelectObject(hDC, holdBmp);
DeleteDC(hDC);
}
DeleteObject(SelectObject(hMemDC, holdBmp));
}
DeleteDC(hMemDC);
}
}
return hRgn;
}
|
|