当前位置: 首页 > news >正文

C++与C#使用GDI+创建PNG并旋转文本的对比实现

以下是使用GDI+在C++和C#中创建PNG图片并写入旋转30度文本的实现对比:

特性C++实现C#实现
代码量约50行约15行
初始化需要显式初始化GDI+环境自动处理GDI+初始化
核心类Gdiplus::BitmapGdiplus::GraphicsSystem.Drawing.BitmapSystem.Drawing.Graphics
旋转实现使用Matrix类或RotateTransform直接使用RotateTransform方法
保存格式需要获取PNG编码器CLSID直接指定保存格式为PNG
资源释放需要手动释放GDI+对象可使用using语句自动释放

C#画图,只要9行代码,VC++要50行代码

VC++纯api调用gdiplus.dll要100行左右的代码

using System.Drawing;
using System.Drawing.Imaging;class Program {static void Main() {// 创建位图using(var bitmap = new Bitmap(400, 200)) {using(var graphics = Graphics.FromImage(bitmap)) {// 设置背景色graphics.Clear(Color.White);// 设置文本属性var font = new Font("Arial", 24);var brush = new SolidBrush(Color.Black);// 旋转并绘制文本graphics.TranslateTransform(100, 50);graphics.RotateTransform(30);graphics.DrawString("helloworld", font, brush, 0, 0);}// 保存为PNGbitmap.Save("output.png", ImageFormat.Png);}}
}

关键差异分析

  1. 初始化过程‌:

    • C++需要显式初始化和清理GDI+环境
    • C#自动处理GDI+的初始化和资源管理
  2. 资源管理‌:

    • C++需要手动释放所有GDI+对象
    • C#可利用using语句自动释放资源
  3. 图像保存‌:

    • C++需要获取PNG编码器的CLSID
    • C#直接使用ImageFormat.Png枚举值
  4. 代码复杂度‌:

    • C++实现需要更多样板代码
    • C#语法更简洁,框架提供了更多便利方法
  5. 旋转实现‌:

    • 两者都使用RotateTransform方法
    • C#的API设计更加直观易用

适用场景建议

  • 选择C++‌:当需要最高性能、直接系统级访问或与现有C++代码库集成时
  • 选择C#‌:当开发效率、代码简洁性和快速原型开发是首要考虑因素时

两种语言都能很好地完成GDI+图像处理任务,但C#的实现通常更为简洁高效,特别是在.NET环境下开发时。

VC++用GDIPLUS库画图,50行代码

#include <windows.h>
#include <gdiplus.h>
#include <iostream>
using namespace Gdiplus;int main() {// 初始化GDI+GdiplusStartupInput gdiplusStartupInput;ULONG_PTR gdiplusToken;GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);// 创建位图Bitmap bitmap(400, 200, PixelFormat32bppARGB);Graphics graphics(&bitmap);// 设置背景色graphics.Clear(Color(255, 255, 255, 255));// 设置文本属性Font font(L"Arial", 24);SolidBrush brush(Color(255, 0, 0, 0));PointF point(100.0f, 50.0f);// 旋转文本30度graphics.TranslateTransform(point.X, point.Y);graphics.RotateTransform(30.0f);graphics.DrawString(L"helloworld", -1, &font, PointF(0, 0), &brush);graphics.ResetTransform();// 保存为PNGCLSID pngClsid;GetEncoderClsid(L"image/png", &pngClsid);bitmap.Save(L"output.png", &pngClsid, NULL);// 清理GDI+GdiplusShutdown(gdiplusToken);return 0;
}// 获取编码器CLSID
int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {UINT num = 0, size = 0;GetImageEncodersSize(&num, &size);if(size == 0) return -1;ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)malloc(size);GetImageEncoders(num, size, pImageCodecInfo);for(UINT i = 0; i < num; i++) {if(wcscmp(pImageCodecInfo[i].MimeType, format) == 0) {*pClsid = pImageCodecInfo[i].Clsid;free(pImageCodecInfo);return i;}}free(pImageCodecInfo);return -1;
}

VC++纯api调用gdiplus.dll要100行左右的代码


#include <windows.h>
#include <objidl.h>
#include <stdio.h>// 手动定义GDI+结构体
typedef struct {UINT32 GdiplusVersion;void* DebugEventCallback;BOOL SuppressBackgroundThread;BOOL SuppressExternalCodecs;
} GdiplusStartupInput;// 声明函数指针类型
typedef int (WINAPI* GdiplusStartupFunc)(ULONG_PTR*, const GdiplusStartupInput*, void*);
typedef void (WINAPI* GdiplusShutdownFunc)(ULONG_PTR);
typedef int (WINAPI* GdipCreateBitmapFromScan0Func)(int, int, int, int, void*, void**);
typedef int (WINAPI* GdipGetImageGraphicsContextFunc)(void*, void**);
typedef int (WINAPI* GdipGraphicsClearFunc)(void*, DWORD);
typedef int (WINAPI* GdipCreateFontFunc)(void*, float, int, int, void**);
typedef int (WINAPI* GdipCreateSolidFillFunc)(DWORD, void**);
typedef int (WINAPI* GdipSetTextRenderingHintFunc)(void*, int);
typedef int (WINAPI* GdipDrawStringFunc)(void*, const WCHAR*, int, void*, void*, void*, void*);
typedef int (WINAPI* GdipSaveImageToFileFunc)(void*, const WCHAR*, void*, void*);
typedef int (WINAPI* GdipDeleteGraphicsFunc)(void*);
typedef int (WINAPI* GdipDeleteFontFunc)(void*);
typedef int (WINAPI* GdipDeleteBrushFunc)(void*);
typedef int (WINAPI* GdipDeleteBitmapFunc)(void*);
typedef int (WINAPI* GdipRotateWorldTransformFunc)(void*, float, int);
typedef int (WINAPI* GdipTranslateWorldTransformFunc)(void*, float, float, int);int main() {HMODULE hGdiplus = LoadLibrary(L"gdiplus.dll");if (!hGdiplus) return 1;// 获取函数地址GdiplusStartupFunc GdiplusStartup = (GdiplusStartupFunc)GetProcAddress(hGdiplus, "GdiplusStartup");GdiplusShutdownFunc GdiplusShutdown = (GdiplusShutdownFunc)GetProcAddress(hGdiplus, "GdiplusShutdown");GdipCreateBitmapFromScan0Func GdipCreateBitmapFromScan0 = (GdipCreateBitmapFromScan0Func)GetProcAddress(hGdiplus, "GdipCreateBitmapFromScan0");GdipGetImageGraphicsContextFunc GdipGetImageGraphicsContext = (GdipGetImageGraphicsContextFunc)GetProcAddress(hGdiplus, "GdipGetImageGraphicsContext");GdipGraphicsClearFunc GdipGraphicsClear = (GdipGraphicsClearFunc)GetProcAddress(hGdiplus, "GdipGraphicsClear");GdipCreateFontFunc GdipCreateFont = (GdipCreateFontFunc)GetProcAddress(hGdiplus, "GdipCreateFont");GdipCreateSolidFillFunc GdipCreateSolidFill = (GdipCreateSolidFillFunc)GetProcAddress(hGdiplus, "GdipCreateSolidFill");GdipSetTextRenderingHintFunc GdipSetTextRenderingHint = (GdipSetTextRenderingHintFunc)GetProcAddress(hGdiplus, "GdipSetTextRenderingHint");GdipDrawStringFunc GdipDrawString = (GdipDrawStringFunc)GetProcAddress(hGdiplus, "GdipDrawString");GdipSaveImageToFileFunc GdipSaveImageToFile = (GdipSaveImageToFileFunc)GetProcAddress(hGdiplus, "GdipSaveImageToFile");GdipDeleteGraphicsFunc GdipDeleteGraphics = (GdipDeleteGraphicsFunc)GetProcAddress(hGdiplus, "GdipDeleteGraphics");GdipDeleteFontFunc GdipDeleteFont = (GdipDeleteFontFunc)GetProcAddress(hGdiplus, "GdipDeleteFont");GdipDeleteBrushFunc GdipDeleteBrush = (GdipDeleteBrushFunc)GetProcAddress(hGdiplus, "GdipDeleteBrush");GdipDeleteBitmapFunc GdipDeleteBitmap = (GdipDeleteBitmapFunc)GetProcAddress(hGdiplus, "GdipDeleteBitmap");GdipRotateWorldTransformFunc GdipRotateWorldTransform = (GdipRotateWorldTransformFunc)GetProcAddress(hGdiplus, "GdipRotateWorldTransform");GdipTranslateWorldTransformFunc GdipTranslateWorldTransform = (GdipTranslateWorldTransformFunc)GetProcAddress(hGdiplus, "GdipTranslateWorldTransform");// 初始化GDI+GdiplusStartupInput gdiplusStartupInput = {1};ULONG_PTR gdiplusToken;GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);// 创建位图(400x200 ARGB格式)void* bitmap;GdipCreateBitmapFromScan0(400, 200, 0, 0x26200A, NULL, &bitmap);// 获取图形上下文void* graphics;GdipGetImageGraphicsContext(bitmap, &graphics);// 设置白色背景GdipGraphicsClear(graphics, 0xFFFFFFFF);// 创建字体和画刷void* font;GdipCreateFont(L"Arial", 24, 0, 0, &font);void* brush;GdipCreateSolidFill(0xFF000000, &brush);// 设置文本渲染质量GdipSetTextRenderingHint(graphics, 4); // AntiAliasGridFit// 旋转30度并绘制文本GdipTranslateWorldTransform(graphics, 100, 50, 0);GdipRotateWorldTransform(graphics, 30.0f, 0);GdipDrawString(graphics, L"helloworld", -1, font, NULL, brush, NULL);// 保存为PNGCLSID pngClsid = {0x557cf406, 0x1a04, 0x11d3, {0x9a, 0x73, 0x00, 0x00, 0xf8, 0x1e, 0xf3, 0x2e}};GdipSaveImageToFile(bitmap, L"output.png", &pngClsid, NULL);// 释放资源GdipDeleteGraphics(graphics);GdipDeleteFont(font);GdipDeleteBrush(brush);GdipDeleteBitmap(bitmap);GdiplusShutdown(gdiplusToken);FreeLibrary(hGdiplus);return 0;
}

以上是直接调用gdiplus.dll实现PNG创建与旋转文本的纯API方案,基于用户历史需求(C++实现)进行扩展:

核心实现原理

通过LoadLibrary/GetProcAddress动态加载gdiplus.dll,手动声明所有必需的函数原型和结构体,完全绕过GDI+头文件依赖。关键步骤包括:

  1. 动态加载gdiplus.dll并获取函数地址
  2. 手动定义GDI+所需的结构体(如GdiplusStartupInput)
  3. 通过函数指针调用GDI+接口

关键实现要点

  1. 动态加载机制‌:通过LoadLibrary/GetProcAddress实现运行时绑定,避免静态链接
  2. 结构体手动定义‌:完全重现GdiplusStartupInput等核心结构体
  3. PNG编码器CLSID‌:硬编码PNG编码器的类标识符(0x557cf406...)避免额外查询
  4. 资源管理‌:严格遵循创建/销毁配对原则,防止内存泄漏
  5. 坐标系变换‌:通过Translate/Rotate组合实现精确的文本旋转定位

对比原GDI+库方案

特性纯API方案GDI+库方案
依赖项仅需gdiplus.dll需要gdiplus.lib和头文件
初始化手动定义所有结构体自动包含预定义结构体
函数调用通过函数指针间接调用直接方法调用
代码量显著增加(需声明所有接口)简洁
灵活性可选择性加载所需函数必须链接完整库
维护性需自行跟踪接口变更微软官方维护

该方案特别适用于需要严格控制依赖或进行GDI+功能裁剪的场景,但需注意所有GDI+接口均需手动声明,开发复杂度较高

http://www.dtcms.com/a/503847.html

相关文章:

  • 动图在线制作网站烟台广告公司网站建设
  • react.js做的网站学室内装修设计
  • 如何处理大数处理技巧(vpa函数
  • 设计模式举例
  • 【Spring Security】安全过滤链
  • 小区媒体网站建设wordpress简易主题
  • 手机网站经典案例wordpress负载均衡上传附件
  • 银川网站建站中企动力做的网站价格区间
  • 兴义网站开发杭州赛虎网站建设
  • 数据库基础概念体系梳理
  • Kotlin Flow 的使用
  • 网站如何做seo上海网站推广方法
  • Qwen2.5技术报告解读:Qwen2.5 Technical Report
  • 操作系统:进程同步问题(一)
  • Linux---终端 I/O 控制接口开发<termios.h>终端输入输出系统
  • Linux 之 【Linux权限】
  • 网站建设策划书范文案例重庆百度关键词推广
  • 健身器材 网站模版wordpress用户系统
  • 两款实用工具分享:下载与网速测试的轻量级解决方案
  • DVWA靶场实战:Web四大经典漏洞攻防全解析
  • 海外网站测速本地网站建设开发信息大全
  • PowerCat命令操作:PowerShell版的Netcat在渗透测试中的应用
  • 域名注册最好的网站南京设计公司前十名
  • 快速定位源码问题:SourceMap的生成/使用/文件格式与历史
  • 湖南移动官网网站建设wordpress 菜单 分隔
  • 邯郸网站建设服务报价全国住房和城乡建设厅官网
  • leetcode 143 重排链表
  • 元宇宙与职业教育的深度融合:重构技能培养的实践与未来
  • 坪山网站建设哪家便宜帝国cms 网站地图 自定义
  • 双拼输入法:提升打字效率的另一种选择