鱼C论坛

 找回密码
 立即注册
查看: 137|回复: 7

图像打印问题

[复制链接]
发表于 2024-11-16 09:41:42 | 显示全部楼层 |阅读模式

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

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

x
我想将一个大图像按图像宽度*100像素高分块加载然后将图像分块依次绘制到指定名称的打印机(比如HP Designjet T730),打印之前可以选择预览打印页面,调用打印机时不要弹出打印机对话框进行静默调用,另外需要设置打印机驱动的纸张为自定义纸张尺寸880mm * 1200mm纵向,打印分辨率为1200dpi,以及可以设置图案的打印位置,比如从纸张的左边和顶边10mm的位置开始打印(偶尔有些文件也需要图像横向居于纸张中间打印),我曾经尝试了使用lpDevMode->dmPosition.x和lpDevMode->dmPosition.y来指定图像的位置,但是使用它以后不管自定义纸张是多大,都会变成A4,图案打印不全,不知道为什么,请问这应该怎么做?
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复

使用道具 举报

发表于 2024-11-16 09:42:53 | 显示全部楼层
要实现您描述的功能,涉及到多个步骤和细节,简述如下:

1. **图像分块**:使用编程语言或图像处理库(如Python的PIL/Pillow库)将大图像按照宽度*100像素的高分块。这可以通过循环切片图像实现。

2. **调用打印机进行静默打印**:这通常需要直接与打印机驱动进行交互,构建和发送打印任务,而不显示打印对话框。通常,操作系统和编程库提供的API可能满足需求。例如,在Windows中,可以使用`PrintDlgEx`函数进行配置和调用。打印任务需要编写代码来设置`DEVMODE`结构。

3. **设置自定义纸张尺寸和打印首选项**:通过`DEVMODE`结构,您可以设置纸张尺寸、分辨率和打印位置。需要注意的是:

   - `dmPaperWidth` 和 `dmPaperLength`: 用于定义自定义纸张尺寸。单位为1/10毫米。
   - `dmPrintQuality`: 用于设置分辨率。
   - `dmPosition.x` 和 `dmPosition.y`: 通常用于微调打印位置,但这可能依赖于驱动程序的支持和正确配置。如果不生效,需要查看驱动程序的文档或制造商指南。

4. **定位与居中打印**:计算打印起始位置。对于固定位置,直接输入偏移量即可;若需居中打印,计算如下:

    - 横向居中:`(纸张宽度 - 图像宽度) / 2`
    - 纵向居中:`(纸张高度 - 图像高度) / 2`

5. **调试与验证**:确保驱动正确安装,版本更新,查看制造商提供的接口文档。注意,有些属性在某些情况下可能依赖特定硬件支持。

6. **程序实现**:可选择C/C++、C#或Python等语言,根据语言特性选择相应库实现。例如,Python可以通过`win32print`模块进行高级打印机操作。

如此复杂的打印设置和管理需要对细节进行认真研究。参考具体API文档和打印机技术文档是关键。

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

使用道具 举报

 楼主| 发表于 2024-11-16 09:44:51 | 显示全部楼层
FishC 发表于 2024-11-16 09:42
要实现您描述的功能,涉及到多个步骤和细节,简述如下:

1. **图像分块**:使用编程语言或图像处理库( ...

请帮我写一下具体的代码,谢谢
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-16 09:45:01 | 显示全部楼层
cxnet 发表于 2024-11-16 09:44
请帮我写一下具体的代码,谢谢


实现这种高级功能需要调用操作系统的打印API,下面我将提供一个Python示例代码,运用`win32print`模块。需要注意,这里的代码是一个框架,仅用于展示如何设置基本属性和打印。在具体实现时,您需要根据实际情况调整代码。
from PIL import Image
import win32print
import win32ui
import win32con

def print_image(image_path, printer_name):
    # 打开图像
    img = Image.open(image_path)
    
    # 打印机 Handle
    printer_handle = win32print.OpenPrinter(printer_name)

    try:
        # 设置DEVMODE以配置打印机参数
        devmode = win32print.GetPrinter(printer_handle, 2)['pDevMode']
        
        # 设置自定义纸张尺寸(880x1200 mm)
        devmode.PaperWidth = 8800  # 1/10 mm
        devmode.PaperLength = 12000  # 1/10 mm
        
        # 设置打印质量为1200dpi
        devmode.PrintQuality = 1200
        
        # 关闭打印机对话框
        devmode.Fields |= win32con.DM_PRINTQUALITY | win32con.DM_PAPERSIZE | win32con.DM_ORIENTATION

        # 创建打印上下文
        hdc = win32ui.CreateDC()
        hdc.CreatePrinterDC(printer_name)
        hdc.StartDoc(image_path)
        hdc.StartPage()

        # 图像缩放和位置计算(如果需要居中打印,调整这里的坐标值)
        img_width, img_height = img.size
        image_scale = 1200 / img_width
        pos_x = 100  # 从左边10mm开始,1/10 mm
        pos_y = 100  # 从上边10mm开始,1/10 mm

        # 绘制图像
        dib = ImageWin.Dib(img)
        dib.draw(hdc.GetHandleOutput(), (pos_x, pos_y, pos_x + int(img_width * image_scale), pos_y + int(img_height * image_scale)))

        # 结束任务
        hdc.EndPage()
        hdc.EndDoc()
        hdc.DeleteDC()

    finally:
        # 关闭打印机
        win32print.ClosePrinter(printer_handle)


# 示例调用
print_image("example.jpg", "HP Designjet T730")

### 注意事项:
1. **环境要求**:这是Windows平台上的代码,`win32print`和`win32ui`需要在Python Win32 Extensions中使用。可以通过`pip install pywin32`安装。

2. **自定义设置**:注意DEVMODE的不同属性配置,操作可能因打印机驱动而不同。如果自定义纸张不起作用,请确保打印机驱动支持并正确安装。

3. **图像处理**:这里不包含图像分块的实现。在打印之前,根据您的需求可以用PIL库实现图像裁切。

4. **调试**:使用时可能需要根据实际硬件调试和适配。

如需深入定制或实现更多功能,请参考相关文档并结合所用平台进行深入开发。

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

使用道具 举报

 楼主| 发表于 2024-11-16 09:47:00 | 显示全部楼层
FishC 发表于 2024-11-16 09:45
实现这种高级功能需要调用操作系统的打印API,下面我将提供一个Python示例代码,运用`win32print`模块 ...

不好意思,我忘记告诉你我是用的C++ MFC写代码了,请麻烦帮我重写一下
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-16 09:47:17 | 显示全部楼层
cxnet 发表于 2024-11-16 09:47
不好意思,我忘记告诉你我是用的C++ MFC写代码了,请 ...


使用C++ MFC实现打印图像的复杂操作确实涉及到不少细节。以下是一段示例代码,演示如何设置打印机、打印图像时不弹出对话框,以及如何调整打印机设置,如纸张尺寸和分辨率。

这段代码仅是个基础框架,需根据您的具体环境和需求进行调整和完善:
#include <afxwin.h>
#include <winspool.h>

void PrintImage(const CString& printerName, const CString& imagePath) {
    // 打开打印机
    HANDLE hPrinter;
    if (!OpenPrinter(printerName.GetBuffer(), &hPrinter, NULL)) {
        AfxMessageBox(_T("Unable to open printer."));
        return;
    }

    // 获取打印机信息
    DWORD needed;
    GetPrinter(hPrinter, 2, NULL, 0, &needed);
    BYTE* pPrinterInfo = new BYTE[needed];
    if (!GetPrinter(hPrinter, 2, pPrinterInfo, needed, &needed)) {
        AfxMessageBox(_T("Unable to get printer info."));
        delete[] pPrinterInfo;
        ClosePrinter(hPrinter);
        return;
    }

    PRINTER_INFO_2* pInfo2 = (PRINTER_INFO_2*)pPrinterInfo;

    // 设置 DEVMODE
    DEVMODE* pDevMode = (DEVMODE*)GlobalLock(pInfo2->pDevMode);
    if (pDevMode) {
        // 设置自定义纸张
        pDevMode->dmFields |= DM_PAPERWIDTH | DM_PAPERLENGTH | DM_PRINTQUALITY;
        pDevMode->dmPaperWidth = 8800;  // 1/10 mm
        pDevMode->dmPaperLength = 12000; // 1/10 mm
        pDevMode->dmPrintQuality = 1200; // DPI

        // 释放 DEVMODE
        GlobalUnlock(pInfo2->pDevMode);
    }

    // 准备 DOCINFO
    DOCINFO docInfo;
    memset(&docInfo, 0, sizeof(DOCINFO));
    docInfo.cbSize = sizeof(DOCINFO);
    docInfo.lpszDocName = _T("Image Print Job");
    docInfo.lpszOutput = NULL;

    // 创建和启动打印机上下文
    CDC printerDC;
    printerDC.Attach(CreateDC(NULL, pInfo2->pPrinterName, NULL, pDevMode));

    if (printerDC.StartDoc(&docInfo) > 0) {
        printerDC.StartPage();

        // 加载图像
        CImage image;
        image.Load(imagePath);

        // 打印图像
        int posX = 100; // 偏移位置
        int posY = 100;
        image.Draw(printerDC.m_hDC, posX, posY);

        printerDC.EndPage();
        printerDC.EndDoc();
    }

    // 释放资源
    delete[] pPrinterInfo;
    printerDC.DeleteDC();
    ClosePrinter(hPrinter);
}

// 示例调用
PrintImage(_T("HP Designjet T730"), _T("path_to_image.jpg"));

### 代码说明:
1. **打开和检查打印机**:使用`OpenPrinter`和`GetPrinter`函数打开和检查打印机。
   
2. **设置打印机参数**:通过`DEVMODE`结构,控制纸张的宽度、高度分辨率等。记得检查`dmFields`字段,以确保需要更改的设置应用成功。

3. **创建打印机上下文**:`CreateDC`函数创建打印上下文,绘制图像。

4. **处理图像**:使用MFC的`CImage`类加载和绘制图像。

### 注意事项:
- **权限和驱动问题**:确保你有足够的权限访问打印机,且打印机驱动支持所有设置。
- **错误处理**: 本示例中没有完备的错误处理,请根据需要补充。
- **环境测试**:在不同的环境中,具体工作方式可能略有不同,请结合设备、驱动文档进行调试。

希望这些信息能帮助到你。如有更多问题或需求,请随时告知。

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

使用道具 举报

 楼主| 发表于 2024-11-16 14:38:31 | 显示全部楼层
FishC 发表于 2024-11-16 09:47
使用C++ MFC实现打印图像的复杂操作确实涉及到不少细节。以下是一段示例代码,演示如何设置打印机、打 ...

通过这个例子可以看出CImage比用Opencv打开的图片大很多而且速度相对很快,不知道可不可以直接将CImage二值图像做膨胀处理,而不使用Opencv库,如果可以请写个代码
想知道小甲鱼最近在做啥?请访问 -> ilovefishc.com
回复 支持 反对

使用道具 举报

发表于 2024-11-16 14:38:46 | 显示全部楼层
cxnet 发表于 2024-11-16 14:38
通过这个例子可以看出CImage比用Opencv打开的图片大很 ...


在不使用OpenCV的情况下,我们可以利用`CImage`和GDI+进行基本的图像处理操作,如二值化和膨胀处理。由于MFC本身并没有直接提供图像膨胀的功能,我们需要手动实现这些操作。

下面是一个基于`CImage`的示例,演示如何实现简单的二值化和膨胀处理:
#include <afxwin.h>
#include <atlimage.h>

// 二值化图像
void BinarizeImage(CImage& image, BYTE threshold) {
    for (int y = 0; y < image.GetHeight(); ++y) {
        for (int x = 0; x < image.GetWidth(); ++x) {
            COLORREF color = image.GetPixel(x, y);
            BYTE gray = (GetRValue(color) + GetGValue(color) + GetBValue(color)) / 3;
            
            if (gray < threshold) {
                image.SetPixel(x, y, RGB(0, 0, 0));  // 黑
            } else {
                image.SetPixel(x, y, RGB(255, 255, 255));  // 白
            }
        }
    }
}

// 膨胀处理
void DilateImage(CImage& image) {
    CImage copy;
    copy.Create(image.GetWidth(), image.GetHeight(), image.GetBPP());
    image.BitBlt(copy.GetDC(), 0, 0, SRCCOPY);
    copy.ReleaseDC();

    for (int y = 1; y < image.GetHeight() - 1; ++y) {
        for (int x = 1; x < image.GetWidth() - 1; ++x) {
            COLORREF color = copy.GetPixel(x, y);
            if (color == RGB(0, 0, 0)) {
                image.SetPixel(x-1, y, RGB(0, 0, 0));
                image.SetPixel(x+1, y, RGB(0, 0, 0));
                image.SetPixel(x, y-1, RGB(0, 0, 0));
                image.SetPixel(x, y+1, RGB(0, 0, 0));
            }
        }
    }
}

int main() {
    CImage image;
    HRESULT hr = image.Load(_T("path_to_image.jpg"));
    if (FAILED(hr)) {
        AfxMessageBox(_T("Failed to load image."));
        return -1;
    }

    // 二值化处理
    BinarizeImage(image, 128);

    // 膨胀处理
    DilateImage(image);

    // 保存结果图像
    hr = image.Save(_T("path_to_modified_image.jpg"));
    if (FAILED(hr)) {
        AfxMessageBox(_T("Failed to save image."));
        return -1;
    }

    return 0;
}

### 说明:
1. **二值化**:将图像转为灰度图,根据阈值(如128)设置像素为全黑或全白。

2. **膨胀处理**:对图像执行简单的膨胀操作,检查每个像素,如果是黑色,将其周围四个像素也设为黑色。

### 注意:
- 这是基本的操作,只能处理单一通道的图像,对于彩色复杂图像的处理可能需要更复杂的算法。
- 可以根据需要调整`BinarizeImage`中的阈值达到不同效果。

这段代码示例展示了如何不依赖OpenCV来进行CImage的基本图像处理。进行更复杂的图像操作会越来越复杂。希望这些信息能帮助到你,若有其他疑问或需求,请随时告知。

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

使用道具 举报

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

本版积分规则

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

GMT+8, 2024-12-22 02:37

Powered by Discuz! X3.4

© 2001-2023 Discuz! Team.

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