(4)Linuxでトレイを切り替える方法
前回も触れましたが、Linuxの場合はJavaからプリンタへトレイの切り替えの指示ができません。選択したプリンタのデフォルトのトレイの用紙を使おうとするという不具合があります。例えば、用紙のカセット(Javaの用語ではトレイ)が2つある EPSON PX-1700FにA4とA3の用紙をセットして、デフォルトを用紙サイズA4、ソース(カセットのこと)を自動選択にしておいて、A3に印刷しようとするとA4に縮小印刷をします。
Java以外のアプリケーションソフト、例えばLibreOfficeなどからの印刷では、用紙サイズの設定に合わせてトレイを自動で切り替えてくれますから、OSやプリンタドライバの問題ではなく、Javaに問題があるのだと推測できます。
私がとっている回避策は、CUPSなどを使って同じプリンタを複数登録をして、それぞれに異なる用紙をデフォルト用紙サイズに設定し、印刷時に異なるプリンタとして選択するというものです。問題なく印刷できます。同じプリンタの複数登録はLinuxではとても簡単にできますが、Windows 10では簡単にはできないようです。USBとWiFiのようにポートが異なる接続を同時にできるものならば可能かもしれません。ただWindowsではJavaからトレイの切り替え指示ができますからその必要はないでしょう。
MP493一台を複数のプリンタとしてデフォルト用紙を変えて登録すると、「PrinterSupported.java」の実行結果は次のようになります。ダイアログでCanon_MP493_chou3を選択した時の出力です。
adachi@debian64:~$ java PrinterSupported 0 lookup-count: 7 Canon_MP493_A4 media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 Canon_MP493_chou3 media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 Canon_MP493_hagaki media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 Canon_MP493_hagaki_fuchinashi media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 Canon_MP493_series media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 Canon_MP493_you2 media-count: 146 119.944 234.95 :Japanese long envelope #3 :83 :0.055999756+0.05000305+0.0=0.10600281 EPSON_EPSON_PX-1700F media-count: 30 120.015 234.985 :Envelope 120 x 235 mm :887 :0.01499939+0.01499939+0.0=0.02999878 Canon_MP493_A4 :Japanese long envelope #3(83)...[1] Canon_MP493_chou3 :Japanese long envelope #3(83)...[1] Canon_MP493_hagaki :Japanese long envelope #3(83)...[1] Canon_MP493_hagaki_fuchinashi :Japanese long envelope #3(83)...[1] Canon_MP493_series :Japanese long envelope #3(83)...[1] Canon_MP493_you2 :Japanese long envelope #3(83)...[1] EPSON_EPSON_PX-1700F :Envelope 120 x 235 mm(887)...[1] Only one or canceled so set to :Japanese long envelope #3 >>selected :Canon_MP493_chou3 :Japanese long envelope #3 Supported true >>set to :Canon_MP493_chou3 :Japanese long envelope #3 :portrait
(5)プリンタのデフォルトの用紙サイズでプリンタを選ぶ
PrintServiceのメソッドにgetDefaultAttributeValue()というものがあります。これでデフォルトの用紙が長形3号になっているプリンタを探すということができます。前項にあるように同じプリンタを複数登録してデフォルトの用紙を替えておけば、実質上トレイを自動で切り替えることになります。
import java.util.*;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
import javax.swing.JOptionPane;
import static javax.swing.JOptionPane.*;
/**
用紙の幅x、高さy(y>=x)がデフォルトになっているプリンタを返す。
複数あるときはダイアログで選択させて返す。
引数にするPrintRequestAttributeSetには次のものをaddする。
1.MediaSiazeName
2.MediaPrintableArea (フィールド変数を使用)
これは陽には戻値としない
from PrinterSupported07.java
2019-08-22 adachi
*/
public class GetPrinterByDefaultSize {
/**フィールド変数は余白と用紙の大きさを比較するときの許容誤差である。
現在はただの定数だが、将来的に変更のためのメソッドを加えられるようにしている。*/
private float L = 10.1f;
private float R = 10.2f;
private float T = 10.3f;
private float B = 10.4f;
private float diff = 2f;
public boolean GETMAPDUMP = false;
public boolean RESULTDUMP = false;
/** インスタンス化して、用紙の幅x、高さy(y>=x)、PrintRequestAttributeSetを引数に
printerSetTo()を使ってサービスを得る。MediaSiazeNameなどはSetに加えられている。*/
public static void main(String[] args) {
int job = 4;
float x=210f;
float y=297f;
switch (args.length) {
case 2:
x = Float.parseFloat(args[0]);
y = Float.parseFloat(args[1]);
break;
case 1:
job = Integer.parseInt(args[0]);
if(job==0) {x=120f; y=235f;} //chou_3
if(job==1) {x=100f; y=148f;} //hagaki
if(job==2) {x=240f; y=332f;} //kaku_2
if(job==3) {x=297f; y=420f;} //A3
if(job==4) {x=210f; y=297f;} //A4
if(job==5) {x=162f; y=229f;} //kaku_6
if(job==6) {x=98f; y=190f;} //you_6
break;
default:
System.out.println("usage: java GetPrinterByDefaultSize n");
System.out.println(" 0:chou3 1:hagaki 2:kaku2 3:A3");
System.out.println(" 4:A4 5:kaku6 6:you6 ");
System.out.println("or java GetPrinterByDefaultSize x y ...");
}
PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
//rqset.add(OrientationRequested.REVERSE_LANDSCAPE);
GetPrinterByDefaultSize supp = new GetPrinterByDefaultSize();
supp.GETMAPDUMP = true;
supp.RESULTDUMP = true;
PrintService sv = supp.printerSetTo(x,y,rqset);
if (sv!=null) {
System.out.println(">>set to :"+sv.getName());
checkSet(rqset);
}else{
System.out.println(">>canceled");
}
}
/** デバグ用 main()からのみ呼ばれる。*/
public static void checkSet(PrintRequestAttributeSet set1){
Media med1 = (Media)set1.get(Media.class);
System.out.print(" :"+med1.toString());
OrientationRequested ori1 =
(OrientationRequested)set1.get(OrientationRequested.class);
System.out.println((ori1!=null)?" :"+ori1.toString():" :portrait");
}
/** 用紙の幅x、高さy(y>=x)がデフォルトになっているプリンタを返す。
複数あるときはダイアログで選択させて返す。
引数のPrintRequestAttributeSetには、デフォルトのMediaSizeNmaeと余白をadd()する。
PrintRequestAttributeSet は明示的には返り値にしていないが、メソッド内の変更はメソッドから
戻った後に有効になっている。これはServiceUI.printDialog()の振る舞いに合わせたものである。*/
public PrintService printerSetTo(float x, float y, PrintRequestAttributeSet rqset){
PrintService sv = null;
Map<PrintService,MediaSizeName> svmap = getMap1(x,y);
if(svmap.size()>0){
PrintService[] ssvs = svmap.keySet().toArray(new PrintService[0]);
if(svmap.size()>1){
sv = (PrintService)showInputDialog(
null, //parent,
"使用するプリンタを選んでください",//message,
"プリンタの選択",//title,
JOptionPane.QUESTION_MESSAGE, //msgTp,
null, //icon,
ssvs, ssvs[0]
);
if (sv == null) return sv;
}else if(svmap.size()==1){
sv = ssvs[0];
}
MediaSizeName msn = svmap.get(sv);
rqset.add(msn);
MediaSize msize = MediaSize.getMediaSizeForName(msn);
float mwidth = msize.getX(MediaPrintableArea.MM);
float mheight = msize.getY(MediaPrintableArea.MM);
MediaPrintableArea mparea = new MediaPrintableArea(
L, T, (mwidth - L - R), (mheight - T - B),
MediaPrintableArea.MM);
rqset.add(mparea);
if(RESULTDUMP){
System.out.print(">>selected :"+sv.getName());
Media med = (Media)rqset.get(Media.class);
System.out.println(" :"+med.toString());
System.out.println(
"Supported "+ sv.isAttributeValueSupported(med, null, rqset));
}
}else{
showMessageDialog(
null,//parent,
x+" × "+y+" の用紙がデフォルトのプリンタがありません",//message,
"残念な報告",//title
JOptionPane.ERROR_MESSAGE //msgTp
);
if(RESULTDUMP){
System.out.print("no printer for : "+x+" × "+y);
}
return sv;
}
return sv;
}
/** (x,y)の用紙がデフォルトになっているサービスをkeyとし、
その用紙のMediaSizeNameを値とするマップを返す
lookupPrintServices()とgetDefaultAttributeValue()を使って作成する。
printerSetTo()から呼ばれるメソッド */
public Map<PrintService,MediaSizeName> getMap1(float x, float y){
PrintService[] svs = PrintServiceLookup.lookupPrintServices(null,null);
if (GETMAPDUMP) System.out.println("lookup-count: "+svs.length);
Map<PrintService,MediaSizeName> svmap = new LinkedHashMap<>();
for (PrintService sv : svs) {
Media media = (Media)sv.getDefaultAttributeValue(Media.class);
if(media instanceof MediaSizeName){
MediaSizeName msn = (MediaSizeName)media;
MediaSize ms = MediaSize.getMediaSizeForName(msn);
if(ms!=null){
float msx = ms.getX(MediaSize.MM);
float msy = ms.getY(MediaSize.MM);
if(diff>=Math.abs(msx-x) && diff>=Math.abs(msy-y)){
if (GETMAPDUMP){
System.out.println(
msx+" "+msy+"\t:"
+msn.toString()+"("+msn.getValue()+")"
+"\t:"+sv.getName());
}
svmap.put(sv,msn);
}
}
}
}
return svmap;
}
}
まとめとプログラム一覧
今回のまとめ
プリンタの選択はPrintServiceLookup.lookupPrintServices()とServiceUI.printDialog()を組み合わせる方法がよく紹介されているが、条件にあったプリンタを特定するにはあまり役に立たない。
PrintServic#getSupportedAttributeValues()を使えばプリンタドライバから情報を得ることができる。これを使ってプリンタと利用可能用紙サイズを用紙の縦横の長さから選び出す「PrinterSupported.java」を作った。得られたプリンタとMediaSizeNameをペアで使って、PrinterJobまたはDocPrintJobの好みの方で印刷できる。
LinuxではJavaからプリンタのトレイを切り替えることができないが、用紙サイズごとにプリンタを登録し、getDefaultAttributeValue()メソッドを利用することで、トレイを切り替えることが可能になる。
プログラム一覧
-
PrinterSelectTest01.java:
条件にあったプリンタを検索して選択する一般的なプログラム -
PrinterSelectTest02.java:
接続されたプリンタから、あらかじめ分かっている名前でプリンタを選択して使う -
SupportedValuesTest.java:
すべてのプリンタについて、getSupportedAttributeValues()を使い、指定の大きさに近い用紙のMediaSizeNameの一覧を取得する。 -
PrinterSupportedTest.java:
用紙の幅x、高さy(y>=x)に、適合するプリンタを調べServiceUI.printDialog()で選択させて返す。 -
PrinterSupported.java:
用紙の幅x、高さy(y>=x)に、適合するプリンタを調べ独自なダイアログで選択させて返す。 -
SomethingPrintable02.java:
PrinterSupportedクラスを使って選択したプリンタ(と用紙)とPrinterJobを使う帳票印刷の典型例 -
WithDocPrintJob.java:
PrinterSupportedクラスを使って選択したプリンタ(と用紙)とDocPrintJobを使う帳票印刷の典型例 -
GetPrinterByDefaultSize.java:
用紙の幅x、高さy(y>=x)がデフォルトになっているプリンタを返す。複数あるときはダイアログで選択させて返す。
