在内存中创建GDI +位图,然后另存为png [英] Creating GDI+ bitmaps in memory and then saving as png

查看:225
本文介绍了在内存中创建GDI +位图,然后另存为png的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我对C ++非常新,并且在编写一个使用GDI +库在内存中创建一个新的位图(因此不打开/读取现有位图)的函数时遇到了麻烦。然后绘制位图;然后将位图保存为png。特别是,我有位图创建和保存代码的问题。我被限制使用代码块,所以不能使用视觉工作室,即使我想。代码如下:

I am very new to C++ and been having trouble with writing a function that uses the GDI+ library to create a new bitmap in memory ( so not opening/reading an existing bitmap); then drawing on the bitmap; before saving the bitmap as a png. In particular, I am having problems with the bitmap creation and saving code. I am constrained to using codeblocks and so can't use visual studios, even if I wanted to. The code is as follows:

#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,0,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:\\test\\test.png", &pngClsid, NULL);
  }

  GdiplusShutdown(gdiplusToken);
}

我使用此代码的问题如下:

The issues I have been having with this code are as follows:


  1. 保存代码未编译时出现错误消息GetEncoderClsid'未在此范围中声明。但是,我直接从Microsoft网站这里,所以不知道我做错了什么,虽然我不认为这是将位图转换为png的正确方法,但我不知道任何替代方法?

  1. The 'saving' code does not compile with an error message of "'GetEncoderClsid' was not declared in this scope". However, I got this direct from the Microsoft website here and so don't know what I am doing wrong, although I don't think this is the proper way of converting bitmap to png but I dont know any alternative way?

当代码编译并运行时(通过注释保存代码),它会在Bitmap * myBitmap = new Bitmap(width,height,PixelFormatCanonical)

When the code is compiled and run (by commenting out the saving code), it then crashes on the line "Bitmap *myBitmap = new Bitmap(width, height, PixelFormatCanonical);" with an error message saying my executable has stopped working.

我已经添加了'gdi32'链接器库, -lgdiplus'作为链接器选项。此外,我已使用此网站来帮助gdi的东西,虽然位图的部分只处理加载现有的位图(不会在内存中创建新的位图)

I have added the 'gdi32' linker library and also '-lgdiplus' as a linker option. Also, I have used this website to help with the gdi stuff although the section on bitmaps only deals with loading existing bitmaps (not creating new ones in memory)

我完全迷失在做什么,所以任何帮助或建议在这件事情是非常赞赏。

I am totally lost on what to do, so any help or advice on this matter is much appreciated.

推荐答案

核心问题是将错误的像素格式传递到位图构造函数 PixelFormatCanonical 不是受支持的像素格式。这是一个位掩码,用于确定像素格式是否是规范的(请参阅 IsCanonicalPixelFormat )。您必须使用真实的像素格式,例如默认的 PixelFormat32bppARGB

The core issue is passing the wrong pixel format to the Bitmap constructor. PixelFormatCanonical is not one of the supported pixel formats. It's a bit mask used to determine whether a pixel format is canonical (see IsCanonicalPixelFormat). You'll have to use a real pixel format, like the default PixelFormat32bppARGB.

输出:

首先是一个用于GDI +初始化的小助手类。这确保了在所有其他对象被销毁之后,执行dor(即调用 GdiplusShutdown )。关于销毁的顺序,它的作用与操作手册中的附加范围相同。此外,它还允许抛出异常。

First up, a small helper class for GDI+ initialization. This ensures, that the d'tor (i.e. the call to GdiplusShutdown) is executed after all other objects have been destroyed. With respect to order of destruction, it serves the same purpose as the additional scope in the OP. In addition, it also allows for exceptions to be thrown.

#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示例检索编码器的类标识符

This code was taken from the MSDN sample 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 +渲染代码。它使用具有自动存储持续时间的对象,使其更紧凑和更安全。

Finally, the GDI+ rendering code. It uses objects with automatic storage duration throughout, making it more compact and safer.

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

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

    //draw on bitmap
    g.DrawLine( &blackpen, 1, 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:\\test\\test.png", &pngClsid, NULL ) )
        throw runtime_error( "Bitmap::Save" );
}

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



注意:看起来像 GetEncoderClsid 不应该是必需的,因为那些是众所周知的常量。但是,尝试传递适当的 WIC CLSID CLSID_WICPngEncoder )到 Bitmap :: Save 只产生一个 FileNotFound 错误。

Note: It looks like GetEncoderClsid shouldn't be required, since those are well-known constants. However, trying to pass the appropriate WIC CLSID (CLSID_WICPngEncoder) to Bitmap::Save only produced a FileNotFound error.

这篇关于在内存中创建GDI +位图,然后另存为png的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆