加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

c – 在内存中创建GDI位图,然后另存为png

发布时间:2020-12-16 10:13:21 所属栏目:百科 来源:网络整理
导读:我是C的新手,在使用GDI库编写函数以在内存中创建新的位图时遇到了麻烦(因此不能打开/读取现有的位图);然后绘制位图;在保存到png之前.特别是,我在创建位图和保存代码方面遇到了问题.我被限制使用代码块,即使我想,我也不能使用视觉工作室.代码如下: #include
我是C的新手,在使用GDI库编写函数以在内存中创建新的位图时遇到了麻烦(因此不能打开/读取现有的位图);然后绘制位图;在保存到png之前.特别是,我在创建位图和保存代码方面遇到了问题.我被限制使用代码块,即使我想,我也不能使用视觉工作室.代码如下:

#include "drawImage.h"
#include <windows.h>
#include <objidl.h>
#include <gdiplus.h>
#include <stdio.h>
#include <iostream>
using namespace std;
using namespace Gdiplus;

drawImage::drawImage(){}

void drawImage::DrawBitmap(int width,int height){
  GdiplusStartupInput gdiplusStartupInput;
  ULONG_PTR           gdiplusToken;
  GdiplusStartup(&gdiplusToken,&gdiplusStartupInput,NULL);

  {
    //Create a bitmap
    Bitmap myBitmap(width,height,PixelFormatCanonical);
    Graphics g(&myBitmap);
    Pen blackpen(Color(255,0),3);

    //draw on bitmap
    int x1 = 1;
    int x2 = 200;
    int y1 = 1;
    int y2 = 200;
    g.DrawLine(&blackpen,x1,y1,x2,y2);

    // Save bitmap (as a png)
    CLSID pngClsid;
    GetEncoderClsid(L"image/png",&pngClsid);
    myBitmap.Save(L"C:testtest.png",&pngClsid,NULL);
  }

  GdiplusShutdown(gdiplusToken);
}

我遇到的问题如下:

>“保存”代码无法编译,并提供错误消息“’GetEncoderClsid’未在此范围内声明”.但是,我从微软网站here直接得到了这个.我不认为这是转换为png的正确方法,但我不知道另一种方法吗?
>编译并运行代码时(通过注释掉保存代码),它会在“Bitmap * myBitmap = new Bitmap(width,PixelFormatCanonical);”行中崩溃.并给出一条错误消息,说我的可执行文件已停止工作.

我添加了’gdi32’链接库以及’-lgdiplus’作为链接器选项.另外,我使用this website来帮助处理gdi的东西,虽然位图部分只涉及加载现有的位图(不在内存中创建新的位图)

我完全迷失了该怎么做,所以对此事的任何帮助或建议都非常感谢.

解决方法

核心问题是将错误的像素格式传递给 Bitmap constructor.PixelFormatCanonical不是受支持的 pixel formats之一.它是一个用于确定像素格式是否规范的掩码(参见 IsCanonicalPixelFormat).你必须使用真正的像素格式,比如默认的PixelFormat32bppARGB.

以下代码生成所需的输出:

首先,一个用于GDI初始化的小助手类.这确保了在所有其他对象被销毁之后执行d’tor(即对GdiplusShutdown的调用).关于破坏的顺序,它与OP中的附加范围具有相同的目的.此外,它还允许抛出异常.

#include <windows.h>
#include <gdiplus.h>
using namespace Gdiplus;
#include <stdexcept>
using std::runtime_error;

struct GdiplusInit {
    GdiplusInit() {
        GdiplusStartupInput inp;
        GdiplusStartupOutput outp;
        if ( Ok != GdiplusStartup( &token_,&inp,&outp ) )
            throw runtime_error( "GdiplusStartup" );
    }
    ~GdiplusInit() {
        GdiplusShutdown( token_ );
    }
private:
    ULONG_PTR token_;
};

此代码取自MSDN示例Retrieving the Class Identifier for an Encoder.

int GetEncoderClsid( const WCHAR* format,CLSID* pClsid )
{
    UINT  num = 0;          // number of image encoders
    UINT  size = 0;         // size of the image encoder array in bytes

    ImageCodecInfo* pImageCodecInfo = NULL;

    GetImageEncodersSize( &num,&size );
    if ( size == 0 )
        return -1;  // Failure

    pImageCodecInfo = (ImageCodecInfo*)( malloc( size ) );
    if ( pImageCodecInfo == NULL )
        return -1;  // Failure

    GetImageEncoders( num,size,pImageCodecInfo );

    for ( UINT j = 0; j < num; ++j )
    {
        if ( wcscmp( pImageCodecInfo[j].MimeType,format ) == 0 )
        {
            *pClsid = pImageCodecInfo[j].Clsid;
            free( pImageCodecInfo );
            return j;  // Success
        }
    }

    free( pImageCodecInfo );
    return -1;  // Failure
}

最后,GDI渲染代码.它使用具有自动存储持续时间的对象,使其更紧凑和更安全.

void drawImage( int width,int height ) {
    GdiplusInit gdiplusinit;

    //Create a bitmap
    Bitmap myBitmap( width,PixelFormat32bppARGB );
    Graphics g( &myBitmap );
    Pen blackpen( Color( 255,0 ),3 );

    //draw on bitmap
    g.DrawLine( &blackpen,1,200,200 );

    // Save bitmap (as a png)
    CLSID pngClsid;
    int result = GetEncoderClsid( L"image/png",&pngClsid );
    if ( result == -1 )
        throw runtime_error( "GetEncoderClsid" );
    if ( Ok != myBitmap.Save( L"C:testtest.png",NULL ) )
        throw runtime_error( "Bitmap::Save" );
}

int main()
{
    drawImage( 200,200 );
    return 0;
}

注意:看起来不需要GetEncoderClsid,因为这些是众所周知的常量.但是,尝试将相应的WIC CLSID(CLSID_WICPngEncoder)传递给Bitmap :: Save只会产生FileNotFound错误.

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读