鱼C论坛

 找回密码
 立即注册
查看: 611|回复: 13

CImage图像dpi设置

[复制链接]
发表于 2024-11-21 12:10:30 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能^_^

您需要 登录 才可以下载或查看,没有账号?立即注册

x
在C++ MFC里怎样保持CImage图像总像素不变的情况下修改图像的dpi,我需要将图像发送到打印机进行打印,如果直接缩小图像尺寸而不提高图像dpi打印出来的图像质量会下降很多,而如果不修改dpi也不修改尺寸哪么打印出来的图像就打印不全,比如打印机的分辨率是300dpi,而CImage的图像是96dpi,所以我想要提高图像的dpi而自动降低图像的宽度和高度,请问怎样写代码
小甲鱼最新课程 -> https://ilovefishc.com
回复

使用道具 举报

发表于 2024-11-21 12:10:44 | 显示全部楼层
在C++ MFC 中使用 `CImage` 修改图像的 DPI 而保持总像素不变,您需要更新图像的 DPI 信息。虽然 `CImage` 本身没有直接设置 DPI 的方法,但是可以通过修改图像的头信息来实现。以下是一个简单的步骤示例:

1. 加载图像
2. 获取图像头信息并修改 DPI 设置
3. 保存图像

以下是一个简单的代码示例:

  1. #include <atlimage.h>

  2. void ChangeImageDPI(const CString& inputPath, const CString& outputPath, int newDPI) {
  3.     CImage image;
  4.     image.Load(inputPath);

  5.     // 获取图像头信息
  6.     BITMAPINFOHEADER* pBMIH = image.GetBitmapInfoHeader();

  7.     // 原始宽度和高度
  8.     int originalWidth = pBMIH->biWidth;
  9.     int originalHeight = pBMIH->biHeight;

  10.     // 新的水平和垂直分辨率
  11.     image.SetResolution(newDPI, newDPI);

  12.     // 根据新的 DPI 自动调整比例
  13.     float scaleFactor = 96.0f / newDPI;  // 假设原始分辨率是 96 DPI
  14.     int newWidth = static_cast<int>(originalWidth * scaleFactor);
  15.     int newHeight = static_cast<int>(originalHeight * scaleFactor);

  16.     // 更新图像尺寸
  17.     CImage newImage;
  18.     newImage.Create(newWidth, newHeight, image.GetBPP(), 0);
  19.     image.StretchBlt(newImage.GetDC(), 0, 0, newWidth, newHeight, 0, 0, originalWidth, originalHeight, SRCCOPY);
  20.     newImage.ReleaseDC();

  21.     // 保存修改后的图像
  22.     newImage.Save(outputPath);
  23.     image.Destroy();
  24.     newImage.Destroy();
  25. }
复制代码


请注意:

- 该示例假设原始图像的 DPI 是 96。如果原始 DPI 不同,需要相应调整 `scaleFactor`。
- 需要包括适当的错误检查,并处理图像格式兼容性问题。
- 在保存图像时,可能需要指定合适的格式以确 DPI 信息得以保留。

以上代码通过调整 DPI 和缩放图像的尺寸来保持总像素不变,这样可以在打印时获得更好的图像质量。希望这可以帮助到你!如果有其他问题,请继续询问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 12:15:54 | 显示全部楼层
FishC 发表于 2024-11-21 12:10
在C++ MFC 中使用 `CImage` 修改图像的 DPI 而保持总像素不变,您需要更新图像的 DPI 信息。虽然 `CImage`  ...

但是CImage库没有GetBitmapInfoHeader和SetResolution成员怎么办?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 12:22:18 | 显示全部楼层
cxnet 发表于 2024-11-21 12:15
但是CImage库没有GetBitmapInfoHeader和SetResolution ...


您说得对,`CImage` 类确实没有 `GetBitmapInfoHeader` 和 `SetResolution` 这样的成员函数。要处理 DPI 设置,可以使用其他方法。以下是如何使用 GDI+ 来完成这一任务:

  1. #include <afxwin.h>
  2. #include <gdiplus.h>
  3. using namespace Gdiplus;

  4. #pragma comment (lib,"Gdiplus.lib")

  5. void ChangeImageDPI(const CString& inputPath, const CString& outputPath, int newDPI) {
  6.     GdiplusStartupInput gdiplusStartupInput;
  7.     ULONG_PTR gdiplusToken;
  8.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  9.     Bitmap* image = new Bitmap(inputPath);

  10.     // 获取原始宽度和高度
  11.     UINT originalWidth = image->GetWidth();
  12.     UINT originalHeight = image->GetHeight();

  13.     // 计算新的宽度和高度以保持图像总像素数不变
  14.     float scaleFactor = newDPI / 96.0f;  // 假设原始分辨率是 96 DPI
  15.     UINT newWidth = static_cast<UINT>(originalWidth / scaleFactor);
  16.     UINT newHeight = static_cast<UINT>(originalHeight / scaleFactor);

  17.     // 创建新的图像并设置分辨率
  18.     Bitmap* newImage = new Bitmap(newWidth, newHeight, image->GetPixelFormat());
  19.     newImage->SetResolution(static_cast<REAL>(newDPI), static_cast<REAL>(newDPI));

  20.     // 绘制缩放的图像
  21.     Graphics graphics(newImage);
  22.     graphics.DrawImage(image, 0, 0, newWidth, newHeight);

  23.     // 保存修改后的图像
  24.     CLSID pngClsid;
  25.     GetEncoderClsid(L"image/png", &pngClsid);
  26.     newImage->Save(outputPath, &pngClsid, NULL);

  27.     delete image;
  28.     delete newImage;
  29.     GdiplusShutdown(gdiplusToken);
  30. }

  31. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  32.     UINT num = 0;
  33.     UINT size = 0;

  34.     GetImageEncodersSize(&num, &size);
  35.     if(size == 0)
  36.         return -1;

  37.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  38.     if(pImageCodecInfo == NULL)
  39.         return -1;

  40.     GetImageEncoders(num, size, pImageCodecInfo);
  41.     for(UINT j = 0; j < num; ++j) {
  42.         if( wcscmp(pImageCodecInfo[j].MimeType, format) == 0 ) {
  43.             *pClsid = pImageCodecInfo[j].Clsid;
  44.             free(pImageCodecInfo);
  45.             return j;
  46.         }
  47.     }

  48.     free(pImageCodecInfo);
  49.     return -1;
  50. }
复制代码


请注意:
- 这段代码示范了如何使用 GDI+ 进行图像操作,包括加载、调整大小和保存。
- 假设原始图像 DPI 为 96,若实际值不同,则需要更准确的 DPI 信息。
- 在加载和保存图像时,可能需要根据具体情况选择合适格式。
- 确保程序初始化和关闭 GDI+。
  
希望这能帮助到您!如有其他问题,请随时询问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 12:42:41 | 显示全部楼层
FishC 发表于 2024-11-21 12:22
您说得对,`CImage` 类确实没有 `GetBitmapInfoHeader` 和 `SetResolution` 这样的成员函数。要处理 DP ...

“GetEncoderClsid”: 找不到标识符
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 12:42:57 | 显示全部楼层
cxnet 发表于 2024-11-21 12:42
“GetEncoderClsid”: 找不到标识符


对于错误“GetEncoderClsid”: 找不到标识符,您需要手动为其编写一个功能以获取指定格式的编码器 CLSID。这个功能可以用于将图像保存为特定格式。请确保您已经将以下辅助函数添加到您的代码中:

  1. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  2.     UINT num = 0;          // 编码器的数量
  3.     UINT size = 0;         // ImageCodecInfo 数组的大小(字节)

  4.     GetImageEncodersSize(&num, &size);
  5.     if(size == 0) {
  6.         return -1;  // 无编码器
  7.     }

  8.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  9.     if(pImageCodecInfo == NULL) {
  10.         return -1;  // 内存分配失败
  11.     }

  12.     GetImageEncoders(num, size, pImageCodecInfo);
  13.     for(UINT j = 0; j < num; ++j) {
  14.         if(wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
  15.             *pClsid = pImageCodecInfo[j].Clsid;
  16.             free(pImageCodecInfo);
  17.             return j;  // 找到匹配的编码器
  18.         }
  19.     }

  20.     free(pImageCodecInfo);
  21.     return -1;  // 未找到编码器
  22. }
复制代码


这是完整的代码,包括此辅助函数。确保将此函数包括在您的代码中,并在调用 `newImage->Save(outputPath, &pngClsid, NULL);` 之前获得正确的编码器 CLSID。

希望这可以解决您的问题!如果还有其他问题,请继续提问。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 12:47:12 | 显示全部楼层
FishC 发表于 2024-11-21 12:42
对于错误“GetEncoderClsid”: 找不到标识符,您需要手动为其编写一个功能以获取指定格式的编码器 CLSI ...

0x00007FF81382A652 (GdiPlus.dll)处(位于 MFCApplication1.exe 中)引发的异常: 0xC0000005: 写入位置 0x0000015AD0F78C90 时发生访问冲突。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 12:47:26 | 显示全部楼层
cxnet 发表于 2024-11-21 12:47
0x00007FF81382A652 (GdiPlus.dll)处(位于 MFCApplica ...


访问冲突通常是由于对无效指针或内存的操作引起的。在使用 GDI+ 时,尤其需要注意以下几点:

1. **初始化 GDI+**:确保在使用 GDI+ 之前正确初始化,它通常在程序启动时进行。确保 `GdiplusStartup` 的返回值表示成功。

2. **检查图像路径**:确认输入路径和输出路径正确,并且输入图像文件存在。

3. **指针正确性**:在使用指针的地方,确保所有指针都被正确初始化且指向有效的内存。

4. **图像格式**:确保你对于图像的操作是支持的格式,比如说 BMP, PNG, JPEG 等。

以下是一个完整的代码进行检查,同时增加一些守护代码:

  1. #include <afxwin.h>
  2. #include <GdiPlus.h>
  3. using namespace Gdiplus;
  4. #pragma comment (lib,"Gdiplus.lib")

  5. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);

  6. void ChangeImageDPI(const CString& inputPath, const CString& outputPath, int newDPI) {
  7.     GdiplusStartupInput gdiplusStartupInput;
  8.     ULONG_PTR gdiplusToken;
  9.     if (GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL) != Ok) {
  10.         AfxMessageBox(_T("Failed to initialize GDI+"));
  11.         return;
  12.     }

  13.     Bitmap* image = new Bitmap(inputPath);
  14.     if (image->GetLastStatus() != Ok) {
  15.         AfxMessageBox(_T("Failed to load image"));
  16.         delete image;
  17.         GdiplusShutdown(gdiplusToken);
  18.         return;
  19.     }

  20.     UINT originalWidth = image->GetWidth();
  21.     UINT originalHeight = image->GetHeight();
  22.     float scaleFactor = newDPI / 96.0f;
  23.     UINT newWidth = static_cast<UINT>(originalWidth / scaleFactor);
  24.     UINT newHeight = static_cast<UINT>(originalHeight / scaleFactor);

  25.     Bitmap* newImage = new Bitmap(newWidth, newHeight, image->GetPixelFormat());
  26.     if (newImage->GetLastStatus() != Ok) {
  27.         AfxMessageBox(_T("Failed to create new image"));
  28.         delete image;
  29.         delete newImage;
  30.         GdiplusShutdown(gdiplusToken);
  31.         return;
  32.     }

  33.     newImage->SetResolution(static_cast<REAL>(newDPI), static_cast<REAL>(newDPI));

  34.     Graphics graphics(newImage);
  35.     if (graphics.DrawImage(image, 0, 0, newWidth, newHeight) != Ok) {
  36.         AfxMessageBox(_T("Failed to draw image"));
  37.         delete image;
  38.         delete newImage;
  39.         GdiplusShutdown(gdiplusToken);
  40.         return;
  41.     }

  42.     CLSID pngClsid;
  43.     if (GetEncoderClsid(L"image/png", &pngClsid) == -1) {
  44.         AfxMessageBox(_T("Failed to get image encoder"));
  45.     } else if (newImage->Save(outputPath, &pngClsid, NULL) != Ok) {
  46.         AfxMessageBox(_T("Failed to save image"));
  47.     }

  48.     delete image;
  49.     delete newImage;
  50.     GdiplusShutdown(gdiplusToken);
  51. }

  52. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  53.     UINT num = 0;
  54.     UINT size = 0;
  55.     GetImageEncodersSize(&num, &size);
  56.     if (size == 0) return -1;

  57.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  58.     if (pImageCodecInfo == NULL) return -1;

  59.     GetImageEncoders(num, size, pImageCodecInfo);
  60.     for (UINT j = 0; j < num; ++j) {
  61.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
  62.             *pClsid = pImageCodecInfo[j].Clsid;
  63.             free(pImageCodecInfo);
  64.             return j;
  65.         }
  66.     }
  67.    
  68.     free(pImageCodecInfo);
  69.     return -1;
  70. }
复制代码


**建议**:
- 检查代码的所有路径(特别是确保输入图像存在)。
- 检查您使用的图像格式是否受支持。
- 使用异常处理(`try/catch`)来捕获可能出现的异常。

以上这些建议和代码可以帮助您定位并解决访问冲突问题。如果仍然存在问题,还请检查环境配置或者其他依赖库的版本问题。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 13:00:56 | 显示全部楼层
FishC 发表于 2024-11-21 12:47
访问冲突通常是由于对无效指针或内存的操作引起的。在使用 GDI+ 时,尤其需要注意以下几点:

1. ** ...

运行会跳到    gdiplusgraphics.h的下面这一行出错,也能生成一个转换后的文件,dpi是可以改变,但是图像的总像素会变小,我是希望总像素保持不变,就像photoshop里的重定图像像素功能
DllExports::GdipDeleteGraphics(nativeGraphics);
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 13:01:11 | 显示全部楼层
cxnet 发表于 2024-11-21 13:00
运行会跳到    gdiplusgraphics.h的下面这一行出错,也 ...


如果您希望在调整 DPI 时保持图像的总像素数不变,可以通过修改图像物理尺寸(宽度和高度)以适应新 DPI,而不是缩放图像。这意味着调整 DPI 信息而不改变图像的像素数据。

以下是一个带有更正逻辑的例子,确保图像的总像素数保持不变:

  1. #include <afxwin.h>
  2. #include <gdiplus.h>
  3. using namespace Gdiplus;
  4. #pragma comment (lib,"Gdiplus.lib")

  5. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);

  6. void ChangeImageDPI(const CString& inputPath, const CString& outputPath, int newDPI) {
  7.     GdiplusStartupInput gdiplusStartupInput;
  8.     ULONG_PTR gdiplusToken;
  9.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  10.     Bitmap* image = new Bitmap(inputPath);
  11.     if (image->GetLastStatus() != Ok) {
  12.         AfxMessageBox(_T("Failed to load image"));
  13.         delete image;
  14.         GdiplusShutdown(gdiplusToken);
  15.         return;
  16.     }

  17.     // 设定新的DPI
  18.     image->SetResolution(static_cast<REAL>(newDPI), static_cast<REAL>(newDPI));

  19.     // 直接保存图像,不改变像素数据
  20.     CLSID pngClsid;
  21.     if (GetEncoderClsid(L"image/png", &pngClsid) == -1) {
  22.         AfxMessageBox(_T("Failed to get image encoder"));
  23.     } else if (image->Save(outputPath, &pngClsid, NULL) != Ok) {
  24.         AfxMessageBox(_T("Failed to save image"));
  25.     }

  26.     delete image;
  27.     GdiplusShutdown(gdiplusToken);
  28. }

  29. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  30.     UINT num = 0;
  31.     UINT size = 0;
  32.     GetImageEncodersSize(&num, &size);
  33.     if (size == 0) return -1;

  34.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  35.     if (pImageCodecInfo == NULL) return -1;

  36.     GetImageEncoders(num, size, pImageCodecInfo);
  37.     for (UINT j = 0; j < num; ++j) {
  38.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
  39.             *pClsid = pImageCodecInfo[j].Clsid;
  40.             free(pImageCodecInfo);
  41.             return j;
  42.         }
  43.     }

  44.     free(pImageCodecInfo);
  45.     return -1;
  46. }
复制代码


### 说明:
1. 我们只更新图像的 DPI 而不改变其实际像素数据。这会影响图像的打印尺寸(即物理尺寸),但不会影响其数字像素大小。
2. 确保您使用合适的格式来保存图像,这里假设为 PNG 格式。
3. 确保正确处理图像加载和保存的错误,以避免进入无效状态。

这种方式在修改图像的 DPI 信息时,不改变图像中实际像素数,因而保持了总像素不变。如果有其他需求或问题,请随时提问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 13:06:34 | 显示全部楼层
FishC 发表于 2024-11-21 13:01
如果您希望在调整 DPI 时保持图像的总像素数不变,可以通过修改图像物理尺寸(宽度和高度)以适应新 DP ...

这次是可以了,但是我发现不是直接将CImage图像进行的修改dpi,而是以Bitmap* image加载的图片进行的dpi修改
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 13:06:48 | 显示全部楼层
cxnet 发表于 2024-11-21 13:06
这次是可以了,但是我发现不是直接将CImage图像进行的 ...


在使用 GDI+ 修改 DPI 时,确实是通过 `Bitmap` 类来处理图像的。`CImage` 类没有直接的方法来修改图像的 DPI,因为 `CImage` 是一个简单的封装类,没有提供访问和设置 DPI 的方法。

不过,可以利用 `CImage` 和 `Bitmap` 之间的转换来实现目的。具体来说,通过 `CImage` 转换为 `Bitmap`,然后利用 `Bitmap` 修改 DPI 后再转换回 `CImage`。

  1. #include <afxwin.h>
  2. #include <gdiplus.h>
  3. using namespace Gdiplus;
  4. #pragma comment(lib, "Gdiplus.lib")

  5. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);

  6. void ChangeCImageDPI(CImage& img, const CString& outputPath, int newDPI) {
  7.     // 初始化 GDI+
  8.     GdiplusStartupInput gdiplusStartupInput;
  9.     ULONG_PTR gdiplusToken;
  10.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  11.     // 从 CImage 创建 Bitmap
  12.     Bitmap bitmap(img.GetWidth(), img.GetHeight(), img.GetPitch(), PixelFormat32bppARGB, (BYTE*)img.GetBits());

  13.     // 设置新 DPI
  14.     bitmap.SetResolution(static_cast<REAL>(newDPI), static_cast<REAL>(newDPI));

  15.     // 保存 Bitmap 为文件
  16.     CLSID pngClsid;
  17.     if (GetEncoderClsid(L"image/png", &pngClsid) == -1) {
  18.         AfxMessageBox(_T("Failed to get image encoder"));
  19.     } else if (bitmap.Save(outputPath, &pngClsid, NULL) != Ok) {
  20.         AfxMessageBox(_T("Failed to save image"));
  21.     }

  22.     // 关闭 GDI+
  23.     GdiplusShutdown(gdiplusToken);
  24. }

  25. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  26.     UINT num = 0, size = 0;
  27.     GetImageEncodersSize(&num, &size);
  28.     if (size == 0) return -1;

  29.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  30.     if (pImageCodecInfo == NULL) return -1;

  31.     GetImageEncoders(num, size, pImageCodecInfo);
  32.     for (UINT j = 0; j < num; ++j) {
  33.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
  34.             *pClsid = pImageCodecInfo[j].Clsid;
  35.             free(pImageCodecInfo);
  36.             return j;
  37.         }
  38.     }
  39.     free(pImageCodecInfo);
  40.     return -1;
  41. }
复制代码


### 说明:
1. **CImage 转 Bitmap**: 创建 `CImage` 对象后,将其数据转为 `Bitmap` 进行 DPI 设置。
2. **DPI 修改**: 使用 `Bitmap` 的 `SetResolution` 方法来设置新的 DPI。
3. **保存修改后的图像**: 使用 GDI+ 提供的保存功能,不会改变图像的像素数据,只是在图像的头信息中修改了 DPI。

通过这种方式,能够保持 `CImage` 作为输入和处理,确保兼容性,并利用 `GDI+ Bitmap` 达成修改 DPI 的目的。如果还有其他问题,请随时问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 2024-11-21 13:08:26 | 显示全部楼层
FishC 发表于 2024-11-21 13:06
在使用 GDI+ 修改 DPI 时,确实是通过 `Bitmap` 类来处理图像的。`CImage` 类没有直接的方法来修改图像 ...

CImage不可以直接修改图像DPI,Mat图像能不能修改dpi呢?能直接修改Mat图像的dpi也可以
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-21 13:08:43 | 显示全部楼层
cxnet 发表于 2024-11-21 13:08
CImage不可以直接修改图像DPI,Mat图像能不能修改dpi ...


在 OpenCV 中,`Mat` 对象本身没有 DPI 的直接概念。`Mat` 主要用于处理图像数据,因此不包含与 DPI 相关的元数据。然而,你可以在保存图像时,使用自定义的方式来设置 DPI 信息。

如果需要将 OpenCV 的 `Mat` 对象保存为图像文件并修改其 DPI,可以通过将其转换为其他格式并使用支持元数据操作的库(如 GDI+)来实现。

以下是如何通过 OpenCV 和 GDI+ 的结合来调整图像 DPI 的示例:

  1. #include <opencv2/opencv.hpp>
  2. #include <objidl.h>
  3. #include <gdiplus.h>
  4. using namespace Gdiplus;
  5. #pragma comment (lib,"Gdiplus.lib")

  6. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid);

  7. void ChangeMatDPI(const cv::Mat& img, const std::string& outputPath, int newDPI) {
  8.     // 初始化 GDI+
  9.     GdiplusStartupInput gdiplusStartupInput;
  10.     ULONG_PTR gdiplusToken;
  11.     GdiplusStartup(&gdiplusToken, &gdiplusStartupInput, NULL);

  12.     // 将 OpenCV 的 Mat 转换为 GDI+ 的 Bitmap
  13.     Bitmap bitmap(img.cols, img.rows, img.step, PixelFormat24bppRGB, img.data);

  14.     // 设置新的 DPI
  15.     bitmap.SetResolution(static_cast<REAL>(newDPI), static_cast<REAL>(newDPI));

  16.     // 保存 Bitmap 为文件
  17.     CLSID pngClsid;
  18.     if (GetEncoderClsid(L"image/png", &pngClsid) == -1) {
  19.         std::cerr << "Failed to get image encoder" << std::endl;
  20.     } else if (bitmap.Save(std::wstring(outputPath.begin(), outputPath.end()).c_str(), &pngClsid, NULL) != Ok) {
  21.         std::cerr << "Failed to save image" << std::endl;
  22.     }

  23.     // 关闭 GDI+
  24.     GdiplusShutdown(gdiplusToken);
  25. }

  26. int GetEncoderClsid(const WCHAR* format, CLSID* pClsid) {
  27.     UINT num = 0, size = 0;
  28.     GetImageEncodersSize(&num, &size);
  29.     if (size == 0) return -1;

  30.     ImageCodecInfo* pImageCodecInfo = (ImageCodecInfo*)(malloc(size));
  31.     if (pImageCodecInfo == NULL) return -1;

  32.     GetImageEncoders(num, size, pImageCodecInfo);
  33.     for (UINT j = 0; j < num; ++j) {
  34.         if (wcscmp(pImageCodecInfo[j].MimeType, format) == 0) {
  35.             *pClsid = pImageCodecInfo[j].Clsid;
  36.             free(pImageCodecInfo);
  37.             return j;
  38.         }
  39.     }
  40.     free(pImageCodecInfo);
  41.     return -1;
  42. }
复制代码


### 说明:
1. **Mat 转 Bitmap**: 将 `cv::Mat` 转换为 `Bitmap`,需要确保 Mat 格式与 GDI+ 兼容(例如,24位RGB)。
2. **设置和保存 DPI**: 使用 `Bitmap` 的 `SetResolution` 方法设置图像的 DPI。
3. **保存文件**: 通过 GDI+ 保存图像,并且可以明确指定编码格式。

这种方法结合使用 OpenCV 和 GDI+ 来实现对图像 DPI 的设置。同样,这不会更改图像的实际像素数据,只是更新图像文件中的元数据,以便应用于打印或其他需要 DPI 信息的操作。

如果还有其他问题,请随时询问!

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|手机版|Archiver|鱼C工作室 ( 粤ICP备18085999号-1 | 粤公网安备 44051102000585号)

GMT+8, 2025-5-10 01:11

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

快速回复 返回顶部 返回列表