鱼C论坛

 找回密码
 立即注册
12
返回列表 发新帖
楼主: cxnet

C++图像保存问题

[复制链接]
 楼主| 发表于 2024-11-15 13:51:03 | 显示全部楼层
FishC 发表于 2024-11-15 12:51
`HPDF_LoadRawImageFromMem` 是一个加载原始图像数据到 PDF 的方式,但直接调用这个函数可能需要用到 l ...

用它HPDF_LoadRawImageFromMem可以正常转成HPDF_Image可以正常输出PDF文件,不过如果我想在同一个页面上添加多张图片应该怎样做呢?
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-15 13:51:24 | 显示全部楼层
cxnet 发表于 2024-11-15 13:51
用它HPDF_LoadRawImageFromMem可以正常转成HPDF_Image ...


要在同一个页面上添加多张图片,可以通过多次调用 `HPDF_Page_DrawImage` 函数来实现。在绘制每张图像时,可以指定不同的位置和大小,以便在页面上布置图像。

下面是一个简单的示例,展示如何在同一页面上绘制多张图像:

  1. #include <iostream>
  2. #include <opencv2/opencv.hpp>
  3. #include <hpdf.h>

  4. void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
  5.     std::cerr << "Error: " << error_no << ", detail: " << detail_no << std::endl;
  6. }

  7. void saveImagesAsPDF(const std::vector<cv::Mat>& images, const std::string& pdfFileName) {
  8.     HPDF_Doc pdf = HPDF_New(error_handler, nullptr);
  9.     if (!pdf) {
  10.         std::cerr << "Failed to create PDF document" << std::endl;
  11.         return;
  12.     }

  13.     HPDF_Page page = HPDF_AddPage(pdf);
  14.     HPDF_Page_SetWidth(page, 595); // A4 Width in points
  15.     HPDF_Page_SetHeight(page, 842); // A4 Height in points

  16.     float ypos = 700; // Starting y-position in points
  17.     for (const auto& image : images) {
  18.         cv::Mat rgb_image;
  19.         cv::cvtColor(image, rgb_image, cv::COLOR_BGR2RGB); // Convert BGR to RGB

  20.         // Create a raw image buffer
  21.         HPDF_UINT width = rgb_image.cols;
  22.         HPDF_UINT height = rgb_image.rows;
  23.         HPDF_UINT size = width * height * 3; // 3 bytes per pixel for RGB
  24.         const HPDF_BYTE* raw_data = rgb_image.ptr();

  25.         // Load the raw image data into the PDF document
  26.         HPDF_Image pdf_image = HPDF_LoadRawImageFromMem(pdf, raw_data, width, height, HPDF_CS_DEVICE_RGB, 8);

  27.         // Draw the image on the PDF page
  28.         float xpos = 50; // x-position in points
  29.         HPDF_Page_DrawImage(page, pdf_image, xpos, ypos, width / 2, height / 2); // Scale image to fit

  30.         ypos -= (height / 2) + 20; // Move y-position down for next image
  31.         if (ypos < 0) break; // Avoid drawing outside the page
  32.     }

  33.     HPDF_SaveToFile(pdf, pdfFileName.c_str());
  34.     HPDF_Free(pdf);
  35. }

  36. int main() {
  37.     // Load your images using OpenCV
  38.     std::vector<cv::Mat> images;
  39.     images.push_back(cv::imread("image1.png"));
  40.     images.push_back(cv::imread("image2.png"));

  41.     // Save images to PDF
  42.     saveImagesAsPDF(images, "output.pdf");

  43.     return 0;
  44. }
复制代码


### 说明:
- **位置调整**:在 `HPDF_Page_DrawImage` 函数中,通过 `xpos` 和 `ypos` 来控制图像在页面上的位置。
- **尺寸调整**:通过调整 `width / 2` 和 `height / 2` 参数,控制输出图像的大小,以适应页面。
- **页面项格式**:在纸张的单位中,通常使用点(points)作为单位。比如A4大小的页面为 595 x 842 点。
- **循环绘制**:通过循环,将每次图像绘制到页面上,并在绘制完一张图像后调整位置以绘制下一张图像。调整 `ypos` 以确保不会超过页面。例如,根据图像数量或总空间调整到新页面。

这样,您就可以在一个 PDF 页面上对多张图像进行灵活定位。

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

使用道具 举报

 楼主| 发表于 2024-11-15 13:58:10 | 显示全部楼层
FishC 发表于 2024-11-15 13:51
要在同一个页面上添加多张图片,可以通过多次调用 `HPDF_Page_DrawImage` 函数来实现。在绘制每张图像 ...

我是直接将一个图片按图片宽度*100像素的高度分块加载到Mat然后依次把分块添加到PDF图片上,不是多个不同文件的图片
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-15 13:58:25 | 显示全部楼层
cxnet 发表于 2024-11-15 13:58
我是直接将一个图片按图片宽度*100像素的高度分块加载 ...


要将一个大图片按块分割并依次放入PDF页面上,可以逐块读取图像数据并绘制到同一个PDF页面。你需要不断更新图像绘制的位置坐标。下面是一个完整的示例,说明如何处理这个任务:

  1. #include <iostream>
  2. #include <opencv2/opencv.hpp>
  3. #include <hpdf.h>

  4. void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
  5.     std::cerr << "Error: error_no=" << error_no << ", detail_no=" << detail_no << std::endl;
  6. }

  7. void saveMatAsPDF(const cv::Mat& image, const std::string& pdfFileName, int blockHeight) {
  8.     HPDF_Doc pdf = HPDF_New(error_handler, nullptr);
  9.     if (!pdf) {
  10.         std::cerr << "Error creating PDF document" << std::endl;
  11.         return;
  12.     }

  13.     HPDF_Page page = HPDF_AddPage(pdf);
  14.     HPDF_Page_SetWidth(page, static_cast<HPDF_REAL>(image.cols));
  15.     HPDF_Page_SetHeight(page, static_cast<HPDF_REAL>(image.rows));

  16.     int y_offset = 0;
  17.     for (int y = 0; y < image.rows; y += blockHeight) {
  18.         int currentBlockHeight = std::min(blockHeight, image.rows - y);
  19.         cv::Mat block = image.rowRange(y, y + currentBlockHeight);

  20.         // Convert the current block to raw RGB data
  21.         cv::Mat block_rgb;
  22.         cv::cvtColor(block, block_rgb, cv::COLOR_GRAY2RGB);
  23.         
  24.         // Create a HPDF_Image from the raw data
  25.         HPDF_Image pdf_image = HPDF_LoadRawImageFromMem(pdf,
  26.             block_rgb.data,
  27.             block_rgb.cols,
  28.             block_rgb.rows,
  29.             HPDF_CS_DEVICE_RGB,
  30.             8);

  31.         // Draw the image block to the PDF page
  32.         HPDF_Page_DrawImage(page, pdf_image, 0, y_offset, block_rgb.cols, block_rgb.rows);

  33.         y_offset += currentBlockHeight;
  34.     }

  35.     HPDF_SaveToFile(pdf, pdfFileName.c_str());
  36.     HPDF_Free(pdf);
  37. }

  38. int main() {
  39.     // Load an example image
  40.     cv::Mat image = cv::imread("example.tif", cv::IMREAD_GRAYSCALE);
  41.     if (image.empty()) {
  42.         std::cerr << "Error loading image" << std::endl;
  43.         return -1;
  44.     }

  45.     // Create a PDF with each block of the image
  46.     saveMatAsPDF(image, "output.pdf", 100);

  47.     return 0;
  48. }
复制代码


### 关键步骤:
1. **错误处理器**: 处理libharu的错误信息。
2. **加载图像**: 使用OpenCV加载大图像,并将其分割为小块。
3. **创建PDF文档**: 利用libharu新建PDF文档和页面。
4. **逐块绘制**: 在PDF页面上逐块绘制图像。
5. **正确处理颜色**: 确保将灰度图像转换为RGB,因为libharu的`HPDF_LoadRawImageFromMem`需要RGB格式。

运行这个脚本将创建一个PDF文件,依次添加分块后的每个图块。这样做有效处理了即便是大图像,因为你无需将完整图像都临时保存在内存中。

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

使用道具 举报

 楼主| 发表于 2024-11-15 14:11:57 | 显示全部楼层
FishC 发表于 2024-11-15 13:58
要将一个大图片按块分割并依次放入PDF页面上,可以逐块读取图像数据并绘制到同一个PDF页面。你需要不断 ...

这样拼好的图片有些问题,它是从图片底部开始分割插入到页面上方了,所以顺序拼接反了
小甲鱼最新课程 -> https://ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-15 14:12:17 | 显示全部楼层
cxnet 发表于 2024-11-15 14:11
这样拼好的图片有些问题,它是从图片底部开始分割插入 ...


要正确地将图像从上到下分块并按照顺序插入PDF页面,您需要在绘制每一块时计算正确的y坐标。因为在PDF坐标系中,(0,0)通常位于页面的左下角,而图像数据通常是从左上角开始的。因此,调整绘制的y坐标是至关重要的。

请参考以下代码示例,它将图像按照正确的上下顺序分块并绘制到PDF页面中:

  1. #include <iostream>
  2. #include <opencv2/opencv.hpp>
  3. #include <hpdf.h>

  4. void error_handler(HPDF_STATUS error_no, HPDF_STATUS detail_no, void* user_data) {
  5.     std::cerr << "ERROR: error_no=" << error_no << ", detail_no=" << detail_no << std::endl;
  6. }

  7. void saveMatAsPDF(const cv::Mat& image, const std::string& pdfFileName, int blockHeight) {
  8.     HPDF_Doc pdf = HPDF_New(error_handler, nullptr);
  9.     if (!pdf) {
  10.         std::cerr << "Failed to create PDF object." << std::endl;
  11.         return;
  12.     }

  13.     HPDF_SetCompressionMode(pdf, HPDF_COMP_ALL);

  14.     HPDF_Page page = HPDF_AddPage(pdf);
  15.     HPDF_Page_SetWidth(page, image.cols);
  16.     HPDF_Page_SetHeight(page, image.rows);

  17.     for (int y = 0; y < image.rows; y += blockHeight) {
  18.         int actualBlockHeight = std::min(blockHeight, image.rows - y);
  19.         cv::Rect roi(0, y, image.cols, actualBlockHeight);
  20.         cv::Mat subImg = image(roi);

  21.         // Create a raw image from the sub-region
  22.         HPDF_Image pdf_image = HPDF_LoadRawImageFromMem(
  23.             pdf, subImg.data, subImg.cols, subImg.rows, HPDF_CS_DEVICE_GRAY, 8);

  24.         if (!pdf_image) {
  25.             std::cerr << "Failed to load image sub-region." << std::endl;
  26.             continue;
  27.         }

  28.         // Draw the image at the correct position, note the PDF coordinates
  29.         HPDF_Page_DrawImage(page, pdf_image, 0, image.rows - (y + actualBlockHeight), image.cols, actualBlockHeight);
  30.     }

  31.     HPDF_SaveToFile(pdf, pdfFileName.c_str());
  32.     HPDF_Free(pdf);
  33. }

  34. int main() {
  35.     cv::Mat image = cv::imread("large_image.tif", cv::IMREAD_GRAYSCALE);
  36.     if (image.empty()) {
  37.         std::cerr << "Image not found or unable to open." << std::endl;
  38.         return -1;
  39.     }

  40.     saveMatAsPDF(image, "output.pdf", 100);  // Adjust blockHeight as needed

  41.     return 0;
  42. }
复制代码


### 代码说明:
1. **图像分块**:通过循环,遍历图像的每个垂直块,将其逐块绘制到页面。
2. **y坐标处理**:每次绘制子图像时,使用 `image.rows - (y + actualBlockHeight)` 计算正确的y坐标,以确保图片从上到下按顺序添加。
3. **HPDF_LoadRawImageFromMem**:这个函数用于将图像数据直接加载为PDF图像对象。
4. **首选构建**:确保 `libhpdf`、`opencv` 包括文件和库文件已正确链接。根据项目设置调整路径。

请根据你的开发环境和库的实际位置修改路径和链接设置。通过这个方法,图像应该会按照正确的顺序从上到下绘制到PDF中。

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2025-5-10 00:17

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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