文字と線を0.1mm単位で指定場所に印刷するプログラム例
Javaで普通に印刷すればこの精度は出せます。理論上はもっと細かくできますが、プリンタの解像度や紙送りなどの動作の精度、湿度による紙の伸びなどでこの辺が妥当なところでしょう。
PrinterJobクラスを使っての印刷で最低限必要なことは2つです。
- Printableなクラスを作ります。この中に文字列と線の大きさ、太さや印字位置などを記述します。
- そのインスタンスをPrinterJobにセットして印刷を指示します。
まずプログラムと実行結果を示してから、この段階で何ができるかを解説します。
import java.awt.BasicStroke;
import java.awt.Color;
import java.awt.Font;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import static java.awt.Font.*;
public class SomethingPrintable00 implements Printable {
@Override
public int print(Graphics g, PageFormat pf, int pageIndex) {
if (pageIndex != 0) return NO_SUCH_PAGE;
Graphics2D g2 = (Graphics2D)g;
g2.setFont(new Font(SERIF, PLAIN, 12));
g2.setStroke(new BasicStroke(0.5f));
float mm2pt = 72/25.4f;
g2.drawString("枠内に文字を書きます", 32.8f*mm2pt, 35.9f*mm2pt);
float x = 30.1f*mm2pt;
float y = 30.2f*mm2pt;
float w = 50.3f*mm2pt;
float h = 8.4f*mm2pt;
Rectangle2D waku = new Rectangle2D.Float(x, y, w, h);
g2.draw(waku);
g2.setFont(new Font(SANS_SERIF, PLAIN, 9));
g2.drawString("9ポイントの文字です", 32.8f*mm2pt, 44.7f*mm2pt);
g2.setFont(new Font(SERIF, PLAIN, 10));
g2.drawString("最も細い線二本を0.5mm間隔で描きます。", 30.1f*mm2pt, 50.0f*mm2pt);
g2.setStroke(new BasicStroke(0f));
Line2D line = new Line2D.Float();
y = 52.0f*mm2pt;
line.setLine(x, y, 50.0f*mm2pt, y);
g2.draw(line);
y = 52.5f*mm2pt;
line.setLine(x, y, 60.0f*mm2pt, y);
g2.draw(line);
g2.drawString("太さ2ポイントの線です。", 30.2f*mm2pt, 60.4f*mm2pt);
g2.setStroke(new BasicStroke(2f));
y = 62.2f*mm2pt;
line.setLine(x, y, 70.2f*mm2pt, y);
g2.draw(line);
return PAGE_EXISTS;
}
public static void main(String[] args) {
PrinterJob pj = PrinterJob.getPrinterJob();
Printable pable = new SomethingPrintable00();
pj.setPrintable(pable);
if (pj.printDialog()) {
try { pj.print(); }
catch (PrinterException e) {
System.err.println(e);
}
}
}
}
実行結果
印刷結果をスキャンした画像です。A4縦で印刷されたものの左上の一部だけです。クリックすると大きくなります。
検証はEPSON PX-1700FとCANON PIXUS MP493で行っています。細かなことを言うとWindows 10のドライバではPX-1700FでA3の使用に問題があり、EPSONのドライバを入れる必要があります。LINUXとMP493の組み合わせでは4mm下がって印刷されます。
うぐいす色(薄い緑)で書かれた部分は説明のため書き加えたところです。印字位置の数字はプログラム内に書かれたものを示しますが実測値ともほぼ一致します。
印刷に使われる座標系は用紙の左上が原点でx軸は右を、y軸は下を向いています。長さの単位はポイントです。1インチ=72ポイントです。プログラム中でmmをポイントに換算して使っています。
デフォルトの余白がいくらかあるはずですが、それにもかかわらず、印字位置は用紙の縁からの距離を指定します。これはちょっと意外でしたが、便利です。
ちなみに、Java API仕様ドキュメントのPaperの項によればデフォルトの余白は25.4mm(1インチ)です。余白の範囲には印字しません。余白の変更の方法は次回に説明します。今回のプログラム例は余白を避けてレイアウトしています。
印刷前にダイアログがでます。デフォルトプリンタに印刷されるようになっていますが、他のプリンタに変更できます。
ダイアログはOSによって多少違います。上に示したのはLinux(Debian 9)とWindows(Windows 10)のものです。Windowsでは、[プロパティ]のボタンが生きていて、プリンタのネイティブな設定ダイアログを開くことができますが、Linuxではできません。
また、Linuxでは用紙や余白の設定をする「ページ設定」のタブがありますが、Windowsではなく、pageDialog()メソッドで別に出す必要があります。これは引数のないprintDialog()メソッドの場合だけの違いのようで、次回に紹介するPrintRequestAttributeSetのインスタンスを引数に取る場合は同じになります。
ダイアログは共通になるはずなのですが、OSの事情やプリンタドライバも絡んでいて、Javaからは細かくコントロールできないようです。
帳票印刷では、印刷ダイアログに到達する前に、用紙の選択や余白のコントロールは済ませなければならないはずです。これをJavaから行う方法は次回以降に取り扱います。
