cimage和gdi绘图效率比较_vc++加载透明png图片方法——GDI+和CImage两种

这几天放假在家无聊编一个程序,在加载png时遇到了麻烦,后来用了两个方法解决了。一个是用GDI+,另外就是用vs.net

MFC自带的CImage。

先看看GDI+的方法

方法1:

1.GDI+画透明图层(alpha)的png图片

stdafx加入如下:

#include //初始化一下com口

#include "GdiPlus.h"

using namespace Gdiplus;

#pragma comment(lib,"gdiplus.lib")

开始初始化:

在app类的声明里(.h)加入:

ULONG_PTR m_gdiplusToken;

InitInstance()里加入://若没有usingnamespace Gdiplus; 就要在前面加Gdiplus::

GdiplusStartupInput gdiplusStartupInput;

GdiplusStartup(&m_gdiplusToken, &gdiplusStartupInput, NULL);

重载ExitInstance,加入GdiplusShutdown(m_gdiplusToken);

int CxxxApp::ExitInstance()

{

// TODO: 在此添加专用代码和/或调用基类

GdiplusShutdown(m_gdiplusToken);

return CWinApp::ExitInstance();

}

显示图片的过程如下CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));

CRect rect;

GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);

Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object

Image image(_T("1.png")); // Construct an image

graphics.DrawImage(&image, 0, 0, image.GetWidth(), image.GetHeight());

delete pDC;

这是用GDI+来显示图片。

2.CImage绘制带alpha透明图层的png图片

用MFC自带的CImage也可以显示,不过要稍微进行转换才能得到正常的带α通道的png图片!

在画图前进行一次转换,其中Image是CImage的对象if (Image.GetBPP() == 32) //确认该图像包含Alpha通道

{

int i;

int j;

for (i = 0; i 

{

for (j = 0; j 

{

byte *pByte = (byte *)Image.GetPixelAddress(i, j);

pByte[0] = pByte[0] * pByte[3] / 255;

pByte[1] = pByte[1] * pByte[3] / 255;

pByte[2] = pByte[2] * pByte[3] / 255;

}

}

}

具体方法如下:

HWND hwnd = GetSafeHwnd(); //获取窗口的HWND

::InvalidateRect( hwnd, NULL, true ); //或者 ::InvalidateRect( hwnd, NULL, false );

::UpdateWindow(hwnd);

//若使用前不想把原来绘制的图片去掉,可以删去上面那三段

CDC *pDC = GetDC();

CImage Image;

Image.Load(strPath);

if (Image.IsNull())

{

MessageBox(_T("没加载成功"));

return -1;

}

if (Image.GetBPP() == 32) //确认该图像包含Alpha通道

{

int i;

int j;

for (i = 0; i 

{

for (j = 0; j 

{

byte *pByte = (byte *)Image.GetPixelAddress(i, j);

pByte[0] = pByte[0] * pByte[3] / 255;

pByte[1] = pByte[1] * pByte[3] / 255;

pByte[2] = pByte[2] * pByte[3] / 255;

}

}

}

Image.Draw(pDC->m_hDC, 0, 0);

Image.Destroy();

ReleaseDC(pDC);

代码中内部的框架是对图像的再次处理,对原来进行了修正,这样得到的更加正常,代码实测如下

绘图后效果

为了方便,封装成一个通用函数:

pWnd是需要显示图片的控件窗口,strPicPath是png图片地址,bAutoFit是否需要自动适应pWnd的窗口bool ShowPNGInCtrl(CWnd* pWnd,const CString& strPicPath,BOOL bAutoFit)

{

if (NULL == pWnd)

{

return false;

}

if (NULL == pWnd->GetSafeHwnd())

{

return false;

}

if (strPicPath.GetLength()GetClientRect(rect);

HRESULT hr;

hr = img.Load(strPicPath);

if (S_OK != hr)

{

return false;

}

std::unique_ptrpDc;

pDc.reset(new CClientDC(pWnd));

if (bAutoFit)

{

if (img.GetWidth()>img.GetHeight())//说明图片是长方形

{

nDw  = rect.Width();

nDh  = (int)(nDw * img.GetHeight() / img.GetWidth());

nDPx = 0;

nDPy = (int)(rect.Height()/2.0 - nDh/2.0);

if (nDh>rect.Height())//说明图片控件是横着放,这时候就要再次缩减

{

nDh =rect.Height();

nDw  =(int)( img.GetWidth()*nDh/img.GetHeight());

nDPy = 0;

nDPx =(int) (rect.Width()/2.0 - nDw/2.0);

}

}

else//说明竖着比较明显

{

nDh  = rect.Height();

nDw  =(int)( img.GetWidth()*nDh/img.GetHeight());

nDPy = 0;

nDPx =(int) (rect.Width()/2.0 - nDw/2.0);

if (nDw>rect.Width())//说明是另外一种情况

{

nDw  = rect.Width();

nDh  = (int)(nDw * img.GetHeight() / img.GetWidth());

nDPx = 0;

nDPy = (int)(rect.Height()/2.0 - nDh/2.0);

}

}

}

else

{

nDw = img.GetWidth();

nDh = img.GetHeight();

}

if (img.GetBPP() == 32) //确认该图像包含Alpha通道

{

int i;

int j;

for (i=0; i

{

for (j=0; jSetStretchBltMode(HALFTONE);

img.Draw(pDc->m_hDC,nDPx,nDPy,nDw,nDh);

//img.TransparentBlt(pDc->m_hDC,nDPx,nDPy,nDw,nDh,RGB(255, 255, 255));

}

catch (...)

{

return false;

}

return true;

}

------------------------------------------------------------------------------------------------------------------------------------------------------------------------------

3.如果图片是在资源里的时候加载方法又不一样

这时需要两个函数,

对于GDI+如下:BOOL ImageFromIDResource(UINT nID, LPCTSTR sTR,Image *&pImg)

{

HINSTANCE hInst = AfxGetResourceHandle();

HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(nID),sTR); // type

if (!hRsrc)

return FALSE;

// load resource into memory

DWORD len = SizeofResource(hInst, hRsrc);

BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);

if (!lpRsrc)

return FALSE;

// Allocate global memory on which to create stream

HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);

BYTE* pmem = (BYTE*)GlobalLock(m_hMem);

memcpy(pmem,lpRsrc,len);

GlobalUnlock(m_hMem);

IStream* pstm;

CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);

// load from stream

pImg=Gdiplus::Image::FromStream(pstm);

// free/release stuff

pstm->Release();

FreeResource(lpRsrc);

GlobalFree(m_hMem);

return TRUE;

}

这时加载图片的代码变为:CClientDC *pDC = new CClientDC(GetDlgItem(IDC_STATIC_PIC));

CRect rect;

GetDlgItem(IDC_STATIC_PIC)->GetWindowRect(&rect);

Graphics graphics(pDC->m_hDC); // Create a GDI+ graphics object

Image *pimage; // Construct an image

ImageFromIDResource(IDB_PNG1,_T("PNG"),pimage);

graphics.DrawImage(pimage, 0, 0,pimage->GetWidth(), pimage->GetHeight());

delete pDC;

用CImage时需要如下函数:BOOL LoadImageFromResource(CImage *pImage, UINT nResID,LPCTSTR lpTyp)

{

if ( pImage == NULL)

return false;

pImage->Destroy();

// 查找资源

HRSRC hRsrc = ::FindResource(AfxGetResourceHandle(), MAKEINTRESOURCE(nResID), lpTyp);

if (hRsrc == NULL)

return false;

// 加载资源

HGLOBAL hImgData = ::LoadResource(AfxGetResourceHandle(), hRsrc);

if (hImgData == NULL)

{

::FreeResource(hImgData);

return false;

}

// 锁定内存中的指定资源

LPVOID lpVoid = ::LockResource(hImgData);

LPSTREAM pStream = NULL;

DWORD dwSize = ::SizeofResource(AfxGetResourceHandle(), hRsrc);

HGLOBAL hNew = ::GlobalAlloc(GHND, dwSize);

LPBYTE lpByte = (LPBYTE)::GlobalLock(hNew);

::memcpy(lpByte, lpVoid, dwSize);

// 解除内存中的指定资源

::GlobalUnlock(hNew);

// 从指定内存创建流对象

HRESULT ht = ::CreateStreamOnHGlobal(hNew, TRUE, &pStream);

if ( ht != S_OK )

{

GlobalFree(hNew);

}

else

{

// 加载图片

pImage->Load(pStream);

GlobalFree(hNew);

}

// 释放资源

::FreeResource(hImgData);

return true;

}

这时加载图片的代码如下:HWND hwnd = GetSafeHwnd(); //获取窗口的HWND

::InvalidateRect( hwnd, NULL, true ); //或者 ::InvalidateRect( hwnd, NULL, false );

::UpdateWindow(hwnd);

CDC *pDC = GetDC();

CImage Image;

LoadImageFromResource(&Image,IDB_PNG1,_T("PNG"));

if (Image.IsNull())

{

MessageBox(_T("没加载成功"));

return;

}

if (Image.GetBPP() == 32) //确认该图像包含Alpha通道

{

int i;

int j;

for (i=0; i

{

for (j=0; jm_hDC,0,0);

Image.Destroy();

ReleaseDC(pDC);

要注意的是,最好把绘图放在OnPaint消息响应里,否则,OnSize消息触发OnPaint重绘时可能会把之前的绘图全部清除

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
要将 BMP 图像转换为 PNG 格式并添透明度,您可以使用 C++ 的第三方库,例如 libpng 和 zlib。以下是一个简单的示例代码,它使用这些库来执行所需的 BMP 到 PNG 转换和透明度添: ``` #include <iostream> #include <fstream> #include <cstring> #include <png.h> #include "CImage.h" void write_png_file(char* file_name, int width, int height, png_bytep* row_pointers) { FILE* fp = fopen(file_name, "wb"); if (!fp) { std::cerr << "Error: Failed to open PNG file for writing\n"; return; } png_structp png_ptr = png_create_write_struct(PNG_LIBPNG_VER_STRING, nullptr, nullptr, nullptr); if (!png_ptr) { std::cerr << "Error: Failed to create PNG write structure\n"; fclose(fp); return; } png_infop info_ptr = png_create_info_struct(png_ptr); if (!info_ptr) { std::cerr << "Error: Failed to create PNG info structure\n"; png_destroy_write_struct(&png_ptr, nullptr); fclose(fp); return; } if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to initialize PNG write\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_init_io(png_ptr, fp); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to write PNG image header\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_set_IHDR(png_ptr, info_ptr, width, height, 8, PNG_COLOR_TYPE_RGBA, PNG_INTERLACE_NONE, PNG_COMPRESSION_TYPE_BASE, PNG_FILTER_TYPE_BASE); png_write_info(png_ptr, info_ptr); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to write PNG image data\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_write_image(png_ptr, row_pointers); if (setjmp(png_jmpbuf(png_ptr))) { std::cerr << "Error: Failed to complete PNG write\n"; png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); return; } png_write_end(png_ptr, nullptr); png_destroy_write_struct(&png_ptr, &info_ptr); fclose(fp); } void bmp_to_png_with_alpha(const char* bmp_file, const char* png_file) { CImage img; if (!img.Load(bmp_file)) { std::cerr << "Error: Failed to load BMP file\n"; return; } int width = img.GetWidth(); int height = img.GetHeight(); png_bytep* row_pointers = new png_bytep[height]; for (int y = 0; y < height; ++y) { row_pointers[y] = new png_byte[4 * width]; for (int x = 0; x < width; ++x) { COLORREF color = img.GetPixel(x, y); png_byte red = GetRValue(color); png_byte green = GetGValue(color); png_byte blue = GetBValue(color); png_byte alpha = (color != RGB(255, 0, 255)) ? 0xFF : 0x00; png_bytep pixel = &(row_pointers[y][4 * x]); pixel[0] = red; pixel[1] = green; pixel[2] = blue; pixel[3] = alpha; } } write_png_file(png_file, width, height, row_pointers); for (int y = 0; y < height; ++y) { delete[] row_pointers[y]; } delete[] row_pointers; } int main() { const char* bmp_file = "test.bmp"; const char* png_file = "test.png"; bmp_to_png_with_alpha(bmp_file, png_file); return 0; } ``` 在这个示例中,我们首先使用 CImage BMP 图像文件。然后,我们遍历每个像素,并将其值转换为 PNG 格式,同时添透明度(即,如果像素值为 RGB(255, 0, 255),则将其 alpha 值设置为 0,否则将其 alpha 值设置为 255)。最后,我们使用 write_png_file() 函数将转换后的 PNG 图像写入磁盘。 请注意,该示例仅提供了一个基本的转换功能。如果您需要处理大量图像或需要更高级的功能(例如,调整大小、旋转或滤镜等),则可能需要使用更强大的图像处理库,例如 OpenCV 或 ImageMagick。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值