cxnet 发表于 2024-10-10 09:36:52

c++打印mat图

在C++ MFC里,怎样将一个Mat图按指定的X和Y坐标以及宽度、高度、dpi打印到系统打印机

FishC 发表于 2024-10-10 09:37:09

在C++ MFC中打印一个`Mat`图像到系统打印机,可以按照以下步骤进行:

1. **初始化OpenCV和MFC环境:**
   确保你已经配置好OpenCV库,并能在MFC项目中使用。

2. **将`Mat`图像转换为适合MFC打印的格式:**
   将图像转换为DIB(Device Independent Bitmap),这个格式便于在MFC中进行打印。

3. **设置打印文档:**
   创建一个`CPrintDialog`对象,让用户选择打印机和设置参数。

4. **启动打印监视:**
   使用`CDC`类来管理打印任务。

5. **绘制图像:**
   将图像绘制到打印设备的上下文(DC)。你需要使用到`CDC::StretchDIBits`或类似的函数来指定位置、宽度和高度。

6. **结束打印:**
   使用`CDC::EndDoc()`函数来完成打印任务。

这里是一个简化的代码示例,帮助你理解如何实现上述步骤:

void CYourClass::PrintImage(const cv::Mat& image, int x, int y, int width, int height, int dpi)
{
    // Step 1: 转换Mat到DIB
    cv::Mat bgr;
    cvtColor(image, bgr, cv::COLOR_BGR2BGRA);// 确保类型正确

    // Step 2: 创建DIB位图信息
    BITMAPINFO bitmapInfo = {0};
    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapInfo.bmiHeader.biWidth = bgr.cols;
    bitmapInfo.bmiHeader.biHeight = -bgr.rows;// 图像倒转
    bitmapInfo.bmiHeader.biPlanes = 1;
    bitmapInfo.bmiHeader.biBitCount = 32;
    bitmapInfo.bmiHeader.biCompression = BI_RGB;

    // Step 3: 打印对话框和打印环境设置
    CPrintDialog printDlg(FALSE);
    if (printDlg.DoModal() == IDCANCEL) return;
    CDC dc;
    dc.Attach(printDlg.GetPrinterDC());
    dc.m_bPrinting = TRUE;

    CString strTitle;
    strTitle.LoadString(AFX_IDS_APP_TITLE);
    DOCINFO di;
    ::ZeroMemory(&di, sizeof(DOCINFO));
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = strTitle;

    BOOL bPrintingOK = dc.StartDoc(&di);// 开始打印任务

    // Step 4: 绘制图片
    dc.StartPage();

    SetStretchBltMode(dc, HALFTONE);
    dc.StretchDIBits(x, y, width, height, 0, 0, bgr.cols, bgr.rows,
                     bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);

    // Step 5: 结束打印任务
    dc.EndPage();
    dc.EndDoc();
    dc.Detach();

}

请注意,这段代码需要根据具体的项目环境稍作调整。确保安装并配置好OpenCV库,并在MFC项目属性中正确设置路径和依赖项。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-10 09:51:14

提示以下错误
错误        C2039        "StretchDIBits": 不是 "CDC" 的成员

FishC 发表于 2024-10-10 09:51:26

cxnet 发表于 2024-10-10 09:51
提示以下错误
错误        C2039        "StretchDIBits": 不是 "CD ...

在MFC应用程序中,你不能直接调用`CDC::StretchDIBits`,因为`StretchDIBits`是Windows API函数,而不是`CDC`类的成员函数。你需要获取设备上下文的句柄,然后使用Windows API函数来进行操作。下面是一个修正过的代码示例:

void CYourClass::PrintImage(const cv::Mat& image, int x, int y, int width, int height, int dpi)
{
    // Step 1: Convert Mat to DIB format
    cv::Mat bgr;
    cv::cvtColor(image, bgr, cv::COLOR_BGR2BGRA);// Make sure type is correct

    // Step 2: Create bitmap info
    BITMAPINFO bitmapInfo = { 0 };
    bitmapInfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
    bitmapInfo.bmiHeader.biWidth = bgr.cols;
    bitmapInfo.bmiHeader.biHeight = -bgr.rows;// Flip image vertically
    bitmapInfo.bmiHeader.biPlanes = 1;
    bitmapInfo.bmiHeader.biBitCount = 32;
    bitmapInfo.bmiHeader.biCompression = BI_RGB;

    // Step 3: Print dialog and get printer DC
    CPrintDialog printDlg(FALSE);
    if (printDlg.DoModal() == IDCANCEL) return;
    CDC dc;
    dc.Attach(printDlg.GetPrinterDC());
    dc.m_bPrinting = TRUE;

    CString strTitle;
    strTitle.LoadString(AFX_IDS_APP_TITLE);
    DOCINFO di;
    ::ZeroMemory(&di, sizeof(DOCINFO));
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = strTitle;

    BOOL bPrintingOK = dc.StartDoc(&di);// Start print job

    // Step 4: Draw the image
    dc.StartPage();

    // Use Windows API (HDC)
    HDC hdc = dc.GetSafeHdc();
    SetStretchBltMode(hdc, HALFTONE);
    ::StretchDIBits(hdc, x, y, width, height, 0, 0, bgr.cols, bgr.rows,
                  bgr.data, &bitmapInfo, DIB_RGB_COLORS, SRCCOPY);

    // Step 5: End the print job
    dc.EndPage();
    dc.EndDoc();
    dc.Detach();
}

确保所有的依赖库如OpenCV已正确配置,并根据你的实际项目环境调整代码。使用Windows API处理位图数据时,要确保各个参数设置正确,以避免图像方向错误或颜色显示不正确。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。

cxnet 发表于 2024-10-10 10:36:47

打印时        dc.StartDoc(&di);// Start print job
报错

FishC 发表于 2024-10-10 10:37:00

cxnet 发表于 2024-10-10 10:36
打印时        dc.StartDoc(&di);// Start print job
报错

在使用`dc.StartDoc(&di);`时,如果报错,可能原因是`DOCINFO`结构体没有正确初始化,或者其他打印机相关设置不对。以下是使用`CDC`进行打印操作的常用步骤以及错误检查:

1. **确保正确初始化`DOCINFO`结构体:**

   DOCINFO di;
   ::ZeroMemory(&di, sizeof(DOCINFO));
   di.cbSize = sizeof(DOCINFO);
   di.lpszDocName = _T("Your Document Name");

   确保变量`di`的成员变量`cbSize`和`lpszDocName`已经正确设置。

2. **打印环境设置:**

   确保你已经从框架中获取了有效的打印设备上下文`CDC`对象。通常,它可以从`CPrintDialog`的`GetPrinterDC()`或其他打印相关功能中获取。

   HDC hdcPrinter = printDialog.GetPrinterDC();
   CDC dc;
   dc.Attach(hdcPrinter);

3. **启动打印文档:**

   在启动打印作业之前,确保任何打印设备相关的错误(如关闭的打印机或未安装的驱动程序)已经处理。

4. **错误检查:**

   在调用`StartDoc`时可以使用一些错误检查来捕捉产生的问题:

   if (dc.StartDoc(&di) <= 0) {
       // Handle the error, for example output an error message
       AfxMessageBox(_T("Failed to start document."));
       return;
   }

5. **打印流程:**
   
   确保按照`StartDoc`,`StartPage`,`EndPage`,`EndDoc`的顺序调用。

示例代码:

// Get the printer device context
CPrintDialog printDialog(FALSE);
if (printDialog.DoModal() == IDOK) {
    CDC dc;
    dc.Attach(printDialog.GetPrinterDC());

    // Initialize DOCINFO structure
    DOCINFO di;
    ::ZeroMemory(&di, sizeof(DOCINFO));
    di.cbSize = sizeof(DOCINFO);
    di.lpszDocName = _T("Your Document Name");

    if (dc.StartDoc(&di) > 0) {
      dc.StartPage();

      // Perform drawing operations here
      // For example: dc.TextOut(0, 0, _T("Hello, Printer!"));

      dc.EndPage();
      dc.EndDoc();
    } else {
      AfxMessageBox(_T("Failed to start document."));
    }

    dc.DeleteDC();
}

通过以上步骤,你应该能够成功启动打印任务。如果仍然遇到问题,可以检查输出错误信息,并确保打印机驱动和设备正常。

以上回复来自 FishC AI 小助理,如未能正确解答您的问题,请继续追问。
页: [1]
查看完整版本: c++打印mat图