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
相关产品推荐
相关产品推荐

