用紙の大きさや印字領域の大きさを返してくれる。今の所、用紙を指定していないので、デフォルトの値が返ってきます。
昔はUSレターなどがデフォルトの用紙でしたが、今回改めて確かめると最近A4になっていました。もっとも、ドライバ設定の問題もあるかもしれません。
double getWidth() 用紙の幅(単位は1/72インチ。つまりはポイント)
double getImageableX() 描画が開始される一番左の座標。用紙の右の縁が0になるので左余白の幅に等しい。
Imageableは画像を展開できるという意味か。
double getImageableWidth() 印字可能域の幅。
double getHeight() 用紙の高さ
double getImageableY() 描画が開始される一番上の座標。用紙の上の縁が0になるので上余白の幅に等しい。
double getImageableHeight() 印字可能域の高さ。
int getOrientation() 描画の向き。用紙は常に縦長に考える
void setOrientation(int orientation) 描画の向きを指定する。スタティックな定数フィールド値が定義されている
| ←─────────── Width ──────────→ | ||
| ImageableX→ | ←─── ImageableWidth ───→ | |
用紙に合わせて拡大縮小しようとか、センタリングしようとかしなければ、気にする必要はありません。
帳票は大きさが決められていて、異なる大きさの紙に書こうとすることはまずないからです。Imageableな範囲を外れても無視(クリップ)されるだけなのでほとんど問題になりません(印刷が切れるというのは問題ですが)。
この余白はプリンタの制約ではなく見栄えのために適当に決められたものですが、プリンタに問い合わせるサービスを使えるなら別の使い道があります。しかし用紙の全面を使えるように努力してきた結果、これもあまり気にしなくても良くなってきています。
Imageableな部分を線で囲むプログラムです。中央部にgetWidth()やgetImageableWidth()で得られる数値と、mmへの換算を印字します。
そのあとで System.out.println() で端末にも数値を書き出します。Printableなクラスのインスタンスのprint()メソッドの働きが少しわかってきます。
package print01;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Font;
import static java.awt.Font.*;
import java.awt.print.PrinterJob;
import java.awt.print.Printable;
import java.awt.print.PageFormat;
import java.awt.print.PrinterException;
import java.awt.BasicStroke;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
public class PageSize 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(SANS_SERIF, PLAIN, 14));
float strw ;
BasicStroke stroke;
strw=0.5f;
stroke = new BasicStroke(strw);
g2.setStroke(stroke);
double x = pf.getImageableX();
double y = pf.getImageableY();
double w = pf.getImageableWidth();
double h = pf.getImageableHeight();
Rectangle2D.Double rectg = new Rectangle2D.Double(x, y, w, h);
g2.draw(rectg);
g2.drawString("x:"+x+"pt y:"+y+"pt w:"+w+"pt h:"+h+"pt",100,200);
double pt2mm = 25.4d/72;
g2.drawString("x:"+x*pt2mm+"mm y:"+y*pt2mm+"mm w:"+w*pt2mm+"mm h:"+h*pt2mm+"mm",100,240);
double pw = pf.getWidth();
double ph = pf.getHeight();
g2.drawString("paper w:"+pw+"pt paper h:"+ph+"pt",100,280);
g2.drawString("paper w:"+pw*pt2mm+"mm paper h:"+ph*pt2mm+"mm",100,320);
System.out.println("pf.getWidth()="+pf.getWidth());
System.out.println("pf.getImageableX()="+pf.getImageableX());
System.out.println("pf.getImageableWidth()="+pf.getImageableWidth());
System.out.println("pf.getHeight()="+pf.getHeight());
System.out.println("pf.getImageableY()="+pf.getImageableY());
System.out.println("pf.getImageableHeight()="+pf.getImageableHeight());
System.out.println();
return PAGE_EXISTS;
}
public static void main(String[] args) {
PrinterJob pj = PrinterJob.getPrinterJob();
pj.setPrintable(new PageSize());
if (pj.printDialog()) {
try { pj.print(); }
catch (PrinterException e) {
System.out.println(e);
}
}
}
}
水色(薄い青)で書かれた部分は実測値(mm)。手書きで書き加えています。
System.out.println()の出力
印刷は一回でも、print()メソッドは2回呼び出されていることがわかります。数値の単位はポイントです。
$ java print01.PageSize pf.getWidth()=595.0 pf.getImageableX()=72.0 pf.getImageableWidth()=468.0 pf.getHeight()=842.0 pf.getImageableY()=72.0 pf.getImageableHeight()=648.0 pf.getWidth()=595.0 pf.getImageableX()=72.0 pf.getImageableWidth()=468.0 pf.getHeight()=842.0 pf.getImageableY()=72.0 pf.getImageableHeight()=648.0
印刷物にも出ていますが、数値をmmにすると
Width 209.9mm ImageableX 25.4mm Imageablewidth 165.1mm Height 297.0mm ImageableY 25.4mm ImageableHeight 228.6mm
A4の大きさは、
210mm ✕ 297mm
printDialog()の様子。用紙サイズはCustomになり、マージンも全部25.4mmになっています。上と左は25.4ですが他は異なりますから、上左の25.4が合っているのはどちらも切りよく1インチにしたということでしょう。。

プログラムはprint()メソッドに省略がありますが、SomethingPrintable.javaなどのprint()メソッドの内容と同じで良いからです。このプログラムは印刷内容に興味はありません。import部分はjavax.print.attribute...関係が増えているので注意
main()の記述は長く感じますが、いままでのものと基本構造は同じです。PrintRequestAttributeSetのインスタンスreqsetに3つの属性をaddして、printDialog()とprint()の引数として加えているだけです。
if(debug){...} の部分はAttributeSetの内容を書き出すためのもので、本来は必要がない部分です。
package print01;
import static java.awt.Font.*;
import java.awt.*;
import java.awt.print.*;
import java.awt.geom.Line2D;
import java.awt.geom.Rectangle2D;
import javax.print.attribute.HashPrintRequestAttributeSet;
import javax.print.attribute.HashPrintJobAttributeSet;
import javax.print.attribute.PrintRequestAttributeSet;
import javax.print.attribute.PrintJobAttributeSet;
import javax.print.attribute.standard.MediaSize;
import javax.print.attribute.standard.MediaSizeName;
import javax.print.attribute.standard.OrientationRequested;
import javax.print.attribute.standard.MediaPrintableArea;
import javax.print.attribute.standard.MediaTray;
import javax.print.attribute.Attribute;
public class RequestSize implements Printable {
@Override
public int print(Graphics g, PageFormat pf, int pageIndex) {
......
......
return PAGE_EXISTS;
}
public static void main(String[] args) {
PrinterJob pj = PrinterJob.getPrinterJob();
PrintRequestAttributeSet reqset = new HashPrintRequestAttributeSet();
MediaSizeName medname = MediaSizeName.ISO_A4;
reqset.add(medname);
MediaSize medsize = MediaSize.getMediaSizeForName(medname);
float medwidth = medsize.getX(MediaPrintableArea.MM);
float medheight = medsize.getY(MediaPrintableArea.MM);
float topmm = 8.8f; //landscape前のTOP
float bottomm = 7.7f;
float leftmm = 6.6f;
float rightmm = 5.5f;
reqset.add(new MediaPrintableArea(
leftmm, topmm,
(medwidth - leftmm - rightmm),
(medheight - topmm - bottomm), MediaPrintableArea.MM));
//reqset.add(OrientationRequested.REVERSE_LANDSCAPE);
//reqset.add(OrientationRequested.LANDSCAPE);
reqset.add(OrientationRequested.PORTRAIT);
pj.setPrintable(new RequestSize()); //printable instance
if (pj.printDialog( reqset )) {
boolean debug = true;
if(debug){
Attribute[] attrs = reqset.toArray();
for(int n=0 ; attrs.length > n ; n++){
System.out.println( attrs[n].getName()+":"+ attrs[n].toString()+";; ");
}
}
try { pj.print( reqset ); }
catch (PrinterException e) {
System.err.println(e);
}
}
}
}
MediaSizeName.ISO_A4; は メディアのサイズの A4(ISO/DIN & JIS) に
MediaPrintableArea の topmm=8.8f などは マージンの 上8.8mm に
OrientationRequested.PORTRAIT は 用紙の向き 縦 にそれぞれ伝えられています。

MediaSizeName を MediaSizeName.ISO_A3; にすると メディアのサイズは A3(ISO/DIN & JIS) になります。

また、A4のまま PORTRAIT を LANDSCAPE にする、つまり
//reqset.add(OrientationRequested.PORTRAIT); reqset.add(OrientationRequested.LANDSCAPE);
とすると、用紙の向きが 横 になり、topmm=8.8f は右のマージンになります。

つまり、MediaPrintableAreaコンストラクタの第二引数のtopmmは、用紙を回転する前のtopで、用紙を右に90度回転させたかのように印刷するという事になります。
用紙を右に回転させたということは、印刷データを左に回転させるという事でもあります。プリンタの中では用紙の向きは固定ですから、この方が現実に近い受け止め方という事になります。インクジェットプリンタで縦の用紙が文書の頭から出てくるならば、左回転すれば文書の右側が先に出てくることになります。linuxではこのとおりになりますが、Windowsでは逆で文書の左側から出てきます。
$ java print01.RequestSize orientation-requested:portrait;; copies:1;; media:iso-a4;; media-printable-area:(6.6,8.8)->(197.9,280.5)mm;;
media-printable-area:の2つめの括弧内は(ImageableWidth,ImageableHeight)です。A4ですから、
210-6.6-5.5=197.9 297-8.8-7.7=280.5
となり、計算は合っています
$ javac print01/RequestSize.java $ java print01.RequestSize orientation-requested:portrait;; media-printable-area:(6.6,8.8)->(284.9,403.5)mm;; copies:1;; media:iso-a3;;
(ImageableWidth,ImageableHeight)も合わせて変化しています。A3ですから、
297-6.6-5.5=284.9 210*2-8.8-7.7=403.5
となり、やはり計算は合っています
給紙装置をトレイ2 にするとこうなります。
$ java print01.RequestSize orientation-requested:portrait;; copies:1;; media:iso-a3;; media-printable-area:(6.6,8.8)->(284.9,403.5)mm;; sun-alternate-media:alternate-media: Paper Tray 2;;
はじめからセットしていない copies がでてこないだけで同じ。
Y:\>java print01.RequestSize media:iso-a3;; orientation-requested:portrait;; media-printable-area:(6.6,8.8)->(284.9,403.5)mm;;
Y:\>java print01.RequestSize media:iso-a4;; orientation-requested:landscape;; media-printable-area:(6.6,8.8)->(197.9,280.5)mm;;
Y:\>java print01.RequestSize media:用紙カセット2;; orientation-requested:landscape;; media-printable-area:(6.6,8.8)->(197.9,280.5)mm;;
給紙装置を指定すると media:iso-a4;;がなくなります。装置に入っている用紙を利用するのでこれはこれで正しいのです。media-printable-area:は変化しないので、印刷範囲は変わらないのかと思ったら、実際には用紙カセット2のA3の用紙にlandscapeで上下がセンタリングされた位置に出てきました。(6.6,8.8)の8.8が無視された形になっています。
Windowsでのスクリーンショット

Debian GNU/Linux 7 (wheezy)で EPSON PX-1700F を使用していますが、トレイ1しか使えていないのです。そこで上記のトレイ2への変更を試しているわけです。Windowsでは自動選択でも、用紙カセット2の指定でもうまく行きます。
linuxではcupsでデフォルトをA3にしなければなりません。上記の出力で sun-alternate-media:alternate-media: あたりが苦しんでいる様子に見えます。