You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Java PageFormat自定义宽幅热感纸尺寸异常:右侧空白过大

问题描述

我正在开发一个Java项目,需要在58mm-110mm(用户可选)的连续热感打印纸上打印内容。目前已成功打印内容,但最终纸张尺寸不符合预期:58mm宽度时打印正常,但使用更宽尺寸时,右侧出现过多空白。

相关代码

获取页面格式方法

public PageFormat getPageFormat(PrinterJob pj) {
    //PageFormat pf = new PageFormat();
    PageFormat pf = pj.getPageFormat(getPrintAttributes());
    Paper paper = pf.getPaper();

    paper.setSize(pw_PX, ph_PX);
    paper.setImageableArea(plm_PX, // left margin
        ptm_PX, // top margin
        piw_PX,
        pih_PX
    );

    // Set orientation and paper
    pf.setOrientation(PageFormat.PORTRAIT);
    pf.setPaper(paper);
    pj.setPrintable(this);

    return pf;
}

创建打印属性方法

// ***************** creating media format
// @return
public HashPrintRequestAttributeSet getPrintAttributes() {
    printAttributes = new HashPrintRequestAttributeSet();

    printAttributes.add(new MediaPrintableArea(
        plm_MM, ptm_MM,
        piw_MM, pih_MM,
        MediaPrintableArea.MM));

    return printAttributes;
}
输出效果

宽幅纸张打印时,右侧出现大量空白,内容仅占据左侧部分区域。

Printable类print方法
@Override
public int print(Graphics g, PageFormat pf, int page) throws 
PrinterException {

    if (page > 0) {
        return NO_SUCH_PAGE;
    }

    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(KEY_TEXT_ANTIALIASING, VALUE_TEXT_ANTIALIAS_ON);
    g2d.translate(pf.getPaper().getImageableX(), 
    pf.getPaper().getImageableY());


    int y = 0;
    //draw headers
    y += h1Height;
    g2d.setFont(h1Font);
    y = drawCenteredString(g2d, companyName, 0, y, (int) piw_PX);

    ...
    (...code goes on to print more)
}

后续在“打印”按钮的函数中,我会调用PrinterJob并设置该Printable类。请问问题出在哪里,能否提供解决方案?


解决方案

问题核心在于纸张尺寸与可打印区域的参数不匹配、单位转换错误,以及打印机驱动对自定义纸张的识别问题。具体原因和解决步骤如下:

1. 修正单位转换逻辑

Java打印API中,Paper.setSize和setImageableArea的参数单位是1/72英寸,而非像素。你直接用像素赋值会导致尺寸计算错误,宽幅纸时可打印区域被错误缩小,出现右侧空白。正确单位转换公式:

  • 毫米转Java打印单位:毫米值 * 72 / 25.4

2. 统一纸张与可打印区域设置

避免同时通过HashPrintRequestAttributeSet和Paper重复设置可打印区域,优先通过Paper保证逻辑一致:

public PageFormat getPageFormat(PrinterJob pj) {
    PageFormat pf = pj.defaultPage();
    Paper paper = pf.getPaper();

    // 转换用户输入的毫米宽度为Java打印单位(1/72英寸)
    double paperWidth = userInputWidthMM * 72 / 25.4;
    // 内容高度转换为打印单位
    double paperHeight = calculatedHeightMM * 72 / 25.4;

    // 设置纸张整体尺寸
    paper.setSize(paperWidth, paperHeight);

    // 设置可打印区域(示例左右边距2mm)
    double leftMargin = 2 * 72 / 25.4;
    double topMargin = 2 * 72 / 25.4;
    double imageableWidth = paperWidth - leftMargin * 2;
    double imageableHeight = paperHeight - topMargin * 2;

    paper.setImageableArea(leftMargin, topMargin, imageableWidth, imageableHeight);

    pf.setOrientation(PageFormat.PORTRAIT);
    pf.setPaper(paper);
    return pf;
}

3. 确保打印机支持自定义纸张

部分热感打印机对自定义纸张支持有限:

  • 在打印机驱动中添加对应宽度的自定义纸张规格(如110mm连续纸)
  • 优先选择打印机预设的宽幅纸类型,避免自定义不被识别:
public HashPrintRequestAttributeSet getPrintAttributes() {
    HashPrintRequestAttributeSet printAttributes = new HashPrintRequestAttributeSet();
    // 若打印机有预设宽幅纸,直接指定(示例,需根据实际型号调整)
    // printAttributes.add(MediaSizeName.CUSTOM_MEDIA);
    // 或保留自定义可打印区域,确保单位正确
    double leftMarginMM = 2;
    double topMarginMM = 2;
    printAttributes.add(new MediaPrintableArea(
        leftMarginMM, topMarginMM,
        userInputWidthMM - leftMarginMM*2, calculatedHeightMM - topMarginMM*2,
        MediaPrintableArea.MM));
    return printAttributes;
}

4. 修正print方法绘制逻辑

避免使用硬编码的piw_PX,直接从PageFormat获取可打印宽度,确保与纸张设置一致:

@Override
public int print(Graphics g, PageFormat pf, int page) throws PrinterException {
    if (page > 0) {
        return NO_SUCH_PAGE;
    }

    Graphics2D g2d = (Graphics2D) g;
    g2d.setRenderingHint(RenderingHints.KEY_TEXT_ANTIALIASING, RenderingHints.VALUE_TEXT_ANTIALIAS_ON);
    g2d.translate(pf.getImageableX(), pf.getImageableY());

    int y = 0;
    y += h1Height;
    g2d.setFont(h1Font);
    // 从PageFormat获取真实可打印宽度
    int imageableWidth = (int) pf.getImageableWidth();
    y = drawCenteredString(g2d, companyName, 0, y, imageableWidth);

    // 其他绘制逻辑均以imageableWidth为宽度基准
    ...
    return PAGE_EXISTS;
}

5. 调试建议

  • 打印pf.getPaper().getWidth()、pf.getImageableWidth()等值,确认纸张尺寸与可打印区域是否符合预期
  • 用固定宽幅纸(如110mm)测试,排除用户输入转换问题

内容的提问来源于stack exchange,提问作者CodeJunior

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 14:47:31