鱼C论坛

 找回密码
 立即注册
查看: 41|回复: 9

C++图像保存问题

[复制链接]
发表于 昨天 13:58 | 显示全部楼层 |阅读模式

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

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

x
这C++ MFC里Mat图片我想保存为Postscript 3语言的*.ps文件应该怎样操作?网上查了很久没找到方法,请提供示例,谢谢!
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 昨天 13:58 | 显示全部楼层
要在C++ MFC中将OpenCV的`Mat`图像保存为PostScript(.ps)文件,直接保存成这种格式可能比较复杂,因为OpenCV本身并不直接支持PostScript格式。

一种可行的办法是:
1. 将`Mat`图像先转换为一种中间格式,比如BMP或PNG。
2. 使用一个支持格式转换的第三方库或工具将该中间格式转换为PostScript格式。

使用ImageMagick是一个常见的选择。以下是简单操作步骤:

1. **安装ImageMagick**:
   确保系统上安装了ImageMagick。

2. **保存为中间格式**:

   使用OpenCV将图像保存为BMP文件:

cv::Mat image;  // 假设这是您的Mat图像
   imwrite("temp_image.bmp", image);

3. **转换为PostScript**:

   可以使用ImageMagick的命令行工具`convert`来完成格式转换:

convert temp_image.bmp output.ps

4. **通过MFC调用系统命令**:

   可以在MFC中使用`system()`函数来调用命令行:

system("convert temp_image.bmp output.ps");

请注意,这只是一个简单的方法示例。实际项目中,您可能需要处理文件路径问题和错误检查等。此外,若计算机上没有ImageMagick,可能需要事先安装其命令行工具才能正常使用。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 18:52 | 显示全部楼层
FishC 发表于 2024-11-14 13:58
要在C++ MFC中将OpenCV的`Mat`图像保存为PostScript(.ps)文件,直接保存成这种格式可能比较复杂,因为Ope ...

还有其它办法可以直接在C++里把图片输出成Postscript 3的*.ps文件吗?我试了通过ImageMagick的转换功能,文件小是可以,但文件几百兆或者几个G的文件转换起来非常慢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 18:52 | 显示全部楼层
cxnet 发表于 2024-11-14 18:52
还有其它办法可以直接在C++里把图片输出成Postscript  ...


在C++中直接将图像输出为PostScript 3(.ps)文件而不依赖于外部工具,您可能需要手动生成PostScript文件。这涉及用C++代码构建PostScript命令并写入文件。

以下是一个简化的示例,说明如何手动创建一个简单的PostScript文件:
#include <opencv2/opencv.hpp>
#include <fstream>
#include <iostream>

void writePostscript(const cv::Mat& image, const std::string& filename) {
    std::ofstream ofs(filename);

    if (!ofs.is_open()) {
        std::cerr << "Unable to open file for writing" << std::endl;
        return;
    }

    // 输出PostScript文件头信息
    ofs << "%!PS-Adobe-3.0\n";
    ofs << "%%BoundingBox: 0 0 " << image.cols << " " << image.rows << "\n";
    
    // 设置图像翻转和大小
    ofs << image.cols << " " << image.rows << " scale\n";
    ofs << image.cols << " " << "0 translate\n";
    
    // 输出图像数据
    ofs << "{<";
    
    for (int y = 0; y < image.rows; y++) {
        const uchar* row_ptr = image.ptr<uchar>(y);
        for (int x = 0; x < image.cols * image.channels(); x++) {
            ofs << std::hex << static_cast<int>(row_ptr[x]);
        }
    }
    ofs << ">} imagemask\n";
    
    ofs << "showpage\n";
    ofs.close();
}

int main() {
    cv::Mat image = cv::imread("your_image.jpg", cv::IMREAD_GRAYSCALE);
    if (image.empty()) {
        std::cerr << "Image not found!" << std::endl;
        return -1;
    }
    
    writePostscript(image, "output.ps");

    return 0;
}

**说明:**
- 这里示例假定图像是单通道(灰度图像),因为PostScript中处理彩色图像会更加复杂。
- PostScript绘图命令需要您了解PostScript语言,它涉及坐标转换、色彩与路径等操作。
- 上述例子简单输出Hex格式,高效的PostScript文件生成通常需要压缩和多种优化。

**注意:**
这种方法灵活性高,但不够简单,特别对于大型图像,生成PostScript数据较为复杂。如果需要完整的PostScript 3功能,可能需要借助专门的第三方库实现。对于庞大文件的效率问题,可能得依赖更高效的算法或在应用层提前压缩处理。您的需求可以被认为是特殊情况,市面上有很多PDF/PostScript库可以用来实现类似功能。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 19:09 | 显示全部楼层
FishC 发表于 2024-11-14 18:52
在C++中直接将图像输出为PostScript 3(.ps)文件而不依赖于外部工具,您可能需要手动生成PostScript文 ...

这段代码不对,虽然能创建出*.ps文件,但它不能打开使用
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 19:10 | 显示全部楼层
cxnet 发表于 2024-11-14 19:09
这段代码不对,虽然能创建出*.ps文件,但它不能打开使 ...


生成有效的PostScript文件需要遵循相应的PostScript语言规范,您必须在文件中手动定义图像数据结构。以下是一个简单的示例,说明如何使用PostScript语法将图像数据写入.ps文件:
#include <opencv2/opencv.hpp>
#include <fstream>
#include <iostream>
#include <string>

void writePostscript(const cv::Mat& image, const std::string& filename) {
    // 确保图像是灰度或彩色
    CV_Assert(image.type() == CV_8UC1 || image.type() == CV_8UC3);

    std::ofstream ofs(filename);
    if (!ofs.is_open()) {
        std::cerr << "Failed to open file for writing: " << filename << std::endl;
        return;
    }

    // PostScript Header
    ofs << "%!PS-Adobe-3.0\n";
    ofs << "%%BoundingBox: 0 0 " << image.cols << " " << image.rows << "\n";
    ofs << "/picstr " << image.cols * (image.type() == CV_8UC3 ? 3 : 1) << " string def\n";
    ofs << image.cols << " " << image.rows << " 8\n";

    if (image.type() == CV_8UC3) {
        ofs << "[ " << image.cols << " 0 0 -" << image.rows << " 0 " << image.rows << " ]\n";
        ofs << "{ currentfile picstr readhexstring pop }\nfalse 3 colorimage\n";
    } else {
        ofs << "[ " << image.cols << " 0 0 -" << image.rows << " 0 " << image.rows << " ]\n";
        ofs << "{ currentfile picstr readhexstring pop }\nimage\n";
    }

    // Write pixel data
    for (int y = 0; y < image.rows; ++y) {
        for (int x = 0; x < image.cols; ++x) {
            if (image.type() == CV_8UC3) {
                cv::Vec3b color = image.at<cv::Vec3b>(y, x);
                ofs << std::hex << (int)color[2] << (int)color[1] << (int)color[0];  // BGR to RGB
            } else {
                uchar gray = image.at<uchar>(y, x);
                ofs << std::hex << (int)gray << (int)gray << (int)gray;
            }
        }
        ofs << "\n";
    }

    ofs << "showpage\n";
    ofs.close();
}

int main() {
    cv::Mat image = cv::imread("your_image.png");
    if (image.empty()) {
        std::cerr << "Image not loaded!" << std::endl;
        return -1;
    }
    writePostscript(image, "output.ps");
    return 0;
}

### 说明:
- 确保OpenCV和C++编译器环境已正确设置。
- 该代码首先检查图像类型(灰度图或彩色图),然后初始化PostScript文件头。
- 使用`vec3b`处理彩色图像,注意将BGR顺序转换为RGB。
- 将每像素颜色值转换为十六进制格式写入文件中。
- 保存后生成的PostScript文件可以通过支持PostScript格式的查看器打开。

这个代码很基础,如果遇到更复杂的图像或者需要转换成矢量图的话,需要根据图像内容和PostScript语言进行拓展。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 19:29 | 显示全部楼层
FishC 发表于 2024-11-14 19:10
生成有效的PostScript文件需要遵循相应的PostScript语言规范,您必须在文件中手动定义图像数据结构。以 ...

还是不对,如果可以输出PDF文件也是可以的,请问怎样输出PDF文件,并且设置图像dpi,主要是黑白二值图,需要输出1200dpi
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 19:30 | 显示全部楼层
cxnet 发表于 2024-11-14 19:29
还是不对,如果可以输出PDF文件也是可以的,请问怎样 ...


要在C++中输出PDF文件并设置DPI,可以使用第三方库如 Cairo。Cairo 允许您创建矢量图形,并可以导出到PDF格式。以下是一个示例,展示如何使用 Cairo 库将黑白二值图像输出为1200 DPI的PDF文件:

1. **安装 Cairo**:首先,确保安装了 Cairo 库并且您的项目已正确配置以使用它。

2. **使用 Cairo 创建 PDF**:

#include <cairo/cairo.h>
   #include <opencv2/opencv.hpp>

   void saveMatAsPDF(const cv::Mat& image, const std::string& filename, double dpi) {
       // 确保图像是单通道
       CV_Assert(image.type() == CV_8UC1);

       // 计算图像尺寸(以点为单位)
       double width_in_points = image.cols * 72.0 / dpi;
       double height_in_points = image.rows * 72.0 / dpi;

       // 创建一个 PDF surface
       cairo_surface_t* surface = cairo_pdf_surface_create(filename.c_str(), width_in_points, height_in_points);
       cairo_t* cr = cairo_create(surface);

       // 设置缩放比例以匹配 DPI
       cairo_scale(cr, width_in_points / image.cols, height_in_points / image.rows);

       // 绘制图像
       for (int y = 0; y < image.rows; ++y) {
           for (int x = 0; x < image.cols; ++x) {
               uchar pixel = image.at<uchar>(y, x);
               double gray = static_cast<double>(pixel) / 255.0;
               cairo_set_source_rgb(cr, gray, gray, gray);
               cairo_rectangle(cr, x, y, 1, 1);
               cairo_fill(cr);
           }
       }

       // 完成并释放资源
       cairo_destroy(cr);
       cairo_surface_destroy(surface);
   }

   int main() {
       // 加载二值图像
       cv::Mat image = cv::imread("binary_image.png", cv::IMREAD_GRAYSCALE);
       if (image.empty()) {
           std::cerr << "Failed to load image.\n";
           return -1;
       }

       // 保存为 PDF,设置 1200 DPI
       saveMatAsPDF(image, "output.pdf", 1200.0);

       return 0;
   }

在上述代码中,`cairo_pdf_surface_create` 创建了一个新的PDF surface。通过设置`cairo_scale`来确保PDF的尺寸和DPI相匹配。图像以灰度方式绘制,通过遍历每个像素为白色或黑色设置cairo上下文。

确保您的项目正确链接到Cairo库,并且Cairo已在您的开发环境中安装,这样代码才能正常工作。对于Windows环境,安装Cairo库可能需要使用Vcpkg或其他包管理工具。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

 楼主| 发表于 昨天 20:26 | 显示全部楼层
FishC 发表于 2024-11-14 19:30
要在C++中输出PDF文件并设置DPI,可以使用第三方库如 Cairo。Cairo 允许您创建矢量图形,并可以导出到P ...

还有别的库可以将二值图输出到PDF并设置图像压缩dpi吗?Cairo库找了很久没找到适合64位的,官网已经很长时间没有更新了
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 昨天 20:26 | 显示全部楼层
cxnet 发表于 2024-11-14 20:26
还有别的库可以将二值图输出到PDF并设置图像压缩dpi吗 ...


除了 Cairo,还有其他库可以用来将图像输出为 PDF,并设置分辨率。常用的库之一是 **PoDoFo** 和 **Poppler**。不过,如果您需要相对简单的解决方案,我建议使用 **libharu**,它是一个轻量级且易于使用的 PDF 库。

下面是一个使用 libharu 库将二值图像输出为 PDF 的示例:

### 使用 libharu 库

1. **安装 libharu**:首先,下载并安装 libharu。可以在其 [GitHub页面](https://github.com/libharu/libharu)上找到相关信息。

2. **使用 libharu 创建 PDF**:

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

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

   void saveImageAsPDF(const cv::Mat& image, const std::string& filename, int dpi) {
       // 初始化 libharu
       HPDF_Doc pdf = HPDF_New(error_handler, nullptr);
       if (!pdf) {
           std::cerr << "Failed to create PDF object." << std::endl;
           return;
       }

       // 创建页面
       HPDF_Page page = HPDF_AddPage(pdf);
       HPDF_Page_SetWidth(page, image.cols * 72.0 / dpi);
       HPDF_Page_SetHeight(page, image.rows * 72.0 / dpi);

       // 遍历图像并绘制
       for (int y = 0; y < image.rows; ++y) {
           for (int x = 0; x < image.cols; ++x) {
               uchar pixel = image.at<uchar>(y, x);
               double gray = pixel / 255.0;

               HPDF_Page_SetRGBFill(page, gray, gray, gray);
               HPDF_Page_Rectangle(page, x * 72.0 / dpi, (image.rows - y - 1) * 72.0 / dpi, 1 * 72.0 / dpi, 1 * 72.0 / dpi);
               HPDF_Page_Fill(page);
           }
       }

       // 保存 PDF
       HPDF_SaveToFile(pdf, filename.c_str());
       HPDF_Free(pdf);
   }

   int main() {
       cv::Mat image = cv::imread("binary_image.png", cv::IMREAD_GRAYSCALE);
       if (image.empty()) {
           std::cerr << "Failed to load image." << std::endl;
           return -1;
       }

       saveImageAsPDF(image, "output.pdf", 1200);
       return 0;
   }

### 注意事项:
- 确保图像是二值的,这样可以在 PDF 中保持简单。
- `libharu`默认情况下不支持压缩。如果需要压缩功能,可能需要手动实现压缩或考虑其他库。
- 使用上述代码时,请确保正确配置OpenCV和libharu的开发环境。

这将帮助您将二值图像转换为具有特定DPI的PDF。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-11-15 02:53

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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