SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

Javaの標準機能だけで実現する帳票印刷

プリンタの検索と選択、そして特に長形3号封筒への印刷

Javaの標準機能だけで実現する帳票印刷 第3回

(2)JISの封筒を指定する方法

 定形郵便の最大サイズである長形3号、A4を折らずに入れる角形2号などの封筒は、MediaSizeにサイズが登録されているのにMediaSizeNameには登録されていないので使うことができません。これは謎な仕様です。

 ところが、プリンタダイアログの「ページ設定」のページでメディアサイズを選択すると、候補に「長形3号」を見つけることができます。OSとプリンタの機種によりこの候補は変わりますから、この情報はJavaの中ではなくプリンタドライバの中にあると考えられます。例えば、Windows 10上のCanon MP493では次のようになります。

長形3号が選択できる
プリンタダイアログで長形3号が選択できる(Windows 10)

 Linux上では名前が「Japanese long envelope #3」となりますが、これが長形3号です。同じプリンタでも内容に差があるのはドライバの設計者が異なるからでしょう。長形3号というJIS規格(読み方は「なががた」)ですが、プリンタやそのドライバで名前が異なるのは困ったことです。

長形3号が選択できる
プリンタダイアログで長形3号が選択できる(Linux)

 Javaからlookupメソッドで使えるプリンタを探すという機能があるわけですから、プリンタドライバからの情報を得る方法はあるはずと考えて、改めてAPIマニュアルからメソッドを探しました。どうやらPrinterServiceインターフェースのgetSupportedAttributeValues()メソッドが使えそうです。

使える用紙の情報をプリンタから取得する

 getSupportedAttributeValues()メソッドはjavax.printパッケージのPrintServiceにあるメソッドです。PrintRequestAttributeSetに指定するような属性のうち、指定したプリンタがサポートしているものを列挙してくれます。長形3号が使えるようになるだけではなく、A3が印刷できるプリンタを特定することもできるかもしれません。

getSupportedAttributes()メソッド
getSupportedAttributeValues
Object getSupportedAttributeValues(Class<? extends Attribute> category,
                                   DocFlavor flavor,
                                   AttributeSet attributes)

 第一引数はAttributeインターフェースを持ったクラス。今回はMedia.classにします。

 第二引数はDocFlavor。今回はnullにします。

 第三引数はAttributeSet。今回はこれもnullにします。MediaSizeNameに登録されていないので長形3号と指定できずに苦労しているのです。

 戻値はObjectです。調べる印刷属性が異なると戻値の型も変わるからですが、あまりスマートでない使い方になります。

 具体的にはこういうことです。svをPrintServiceのインスタンスとして、次のようにします。

Media[] meds = (Media[])sv.getSupportedAttributeValues(Media.class, null, null);

 引数をMedia.classにすると、プリンタがサポートする属性のうち、Media.classな要素が格納されたObjectの配列が戻ってきます。それをMediaクラスの配列にキャストしてMediaクラスの配列に代入します。

 Mediaクラスにはさらにサブクラスがあります。このMedia[]の要素は、MediaSizeNameかMediaNameかMediaTrayかのどれかです。実際にはほとんどがMediaSizeNameです。全部の要素を調べて、それがMediaSizeNameだった時に、さらにMediaSizeを求めます。

for (Media med : meds) {
    if(med instanceof MediaSizeName){
        MediaSizeName msn = (MediaSizeName)med;
        MediaSize ms = MediaSize.getMediaSizeForName(msn);

 MediaSizeが分かれば、これからgetX()とgetY()で、次のように用紙の縦横の長さがmm単位で分かるということです。

float msx = ms.getX(MediaSize.MM);
float msy = ms.getY(MediaSize.MM);

 このようにして、それぞれのPrintServiceから使用できるすべての用紙の縦横の長さと、そのMediaSizeNameを取得できます。縦横の長さで比較して、一致したらそのMediaSizeNameを使うという段取りになります。

 このMediaSizeNameにはjavax.print.attribute.standardにないものも含まれています。toString()メソッドで文字列表現を得ることができます。しかし、長形3号の場合、MediaSizeNameは「長形3号」であったり、「Japanese long envelope #3」であったりと、プリンタに依存しますから、名前で特定することができません。

getSupportedAttributeValues()メソッドを使うプログラム

 どのようにデータが得られるかテストプログラムを書いてみます。これは、OSやプリンタ、プリンタドライバ、あるいはJavaのバージョンが変わった時に再検証するためでもあります。

SupportedValuesTest.java
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.*;
/** 
 SupportedValuesTest.java
 すべてのプリンタについて.getSupportedAttributeValues()から
 MediaSizeNameの一覧を取得。
 MediaSizeを経由して用紙のX,Yを取得し、
 指定の大きさに近い用紙名を書き出す。
 起動時引数により、長形3号,葉書,A3,A4に切り替える。
 2019-07-18
 Adachi
*/
public class SupportedValuesTest {
    public static void main(String[] args) {
        float x = 0;
        float y = 0;
        int job = 1;
        if (args.length==0) {
           System.out.println("1:chou_3  2:postcard 3:A3  4:A4");
       }
        if (args.length>0) job = Integer.parseInt(args[0]);
        if(job==1) {x=120f; y=235f;} //chou_3
        if(job==2) {x=100f; y=148f;} //hagaki
        if(job==3) {x=297f; y=420f;} //A3
        if(job==4) {x=210f; y=297f;} //A4

        PrintRequestAttributeSet rqset = new HashPrintRequestAttributeSet();
        DocFlavor flv = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintService[] svs = PrintServiceLookup.lookupPrintServices(flv,rqset);
        for(PrintService sv:svs){
            System.out.println(sv.getName());
            printerSupportedAtrributes(sv,x,y);
        }
    }

    public static void printerSupportedAtrributes(PrintService sv,float x,float y){
        MediaSizeName retmsn = null;
        Media[] meds = (Media[])sv.getSupportedAttributeValues(Media.class, null, null);
        for (Media med : meds) {
            if(med instanceof MediaSizeName){
                MediaSizeName msn = (MediaSizeName)med;
                MediaSize ms = MediaSize.getMediaSizeForName(msn);
                if(ms!=null){
                    float msx = ms.getX(MediaSize.MM);
                    float msy = ms.getY(MediaSize.MM);
                    if(2>=Math.abs(msx-x) && 2>=Math.abs(msy-y)){
                        System.out.print("  "+msx+" "+msy+" : ");
                        System.out.println(msn.toString()+"("+msn.getValue()+")");
                    }
                 }
            }
        }
    }
}

実行結果(Windows 10)

 起動時の引数を1として幅と高さが120mmと235mmつまり長形3号を探しています。

実行時の端末表示(Windows)
PS Z:\java\print01> java SupportedValuesTest 1
OneNote
Microsoft XPS Document Writer
  120.0 235.0 : 封筒 長形 3 号(20)
Microsoft Print to PDF
Fax
  120.0 235.0 : 封筒 長形 3 号(20)
EPSON PX-1700F
  120.0 235.0 : 長形3号封筒 120 x 235 mm(101)
Canon MP493 series Printer
  120.0 235.0 : 長形3号(112)
Canon Inkjet iP9910
  120.0 235.0 : 長形3号(112)

 OneNoteからFaxまでは仮想的なプリンタで、OneNoteと"Microsoft Print to PDF"には合致したものがなかったということです。

 PX-1700Fで、見つかったのは1つで、幅、高さが120.0,235.0、NediaSizeNameを文字列化すると「長形3号封筒 120 x 235 mm」です。

 MP493 series Printerでは、見つかったのはやはり1つで、幅、高さが120.0,235.0、NediaSizeNameを文字列化すると「長形3号」です。

実行結果(Linux)

 Linuxでは接続されている物理的なプリンタの2台のみ表示されます。

 縦横の長さが、きりの良い数値でありません。

実行時の端末表示(Linux)
adachi@debian64:~$ java SupportedValuesTest 1
Canon_MP493_series
  119.944 234.95 : Japanese long envelope #3(83)
EPSON_EPSON_PX-1700F
  120.015 234.985 : Envelope 120 x 235 mm(887)

WindowsでもLinuxでも

 (101)などのカッコ内の数値はgetValue()で調べた整数値で、この整数値がMediaSizeNameからMediaSizeを得る時のキーになっているようです。この整数値はJavaの標準にあるMediaSizeNameではプリンタが異なっても同一ですが、ないものはプリンタごとに異なります。また、OSが再起動されるなどで異なる値が割り当てられます。

 どちらにしても、印刷時には見つかったMediaSizeNameと、MediaSizeから計算したMediaPrintableAreaをPrintRequestAttributeSetに加えたものを指定して印刷すればうまく行きます。

葉書、A3、A4に適用してみる

 葉書、A3、A4については、getSupportedAttributeValues()メソッドを使わなくてもMediaSizeNameを指定できるのですが、上記の「SupportedValuesTest.java」を使って調べてみます。1つのプリンタに対してサイズが合致するMediaSizeNmaeが複数になる場合があるので、MediaSizeNmaeのリストとして表を作っています。仮想プリンタは省いてあります。getSupportedAttributeValues()を使うにあたって考慮すべき点が見えてきます。

葉書

 Windows 10の場合です。PX-1700Fは葉書の100x148に近い用紙が2つ合致します。98mmは2mm以内なので「洋形3号封筒 98 x 148 mm」も合致と判断されました。

プリンタがサポートする用紙(Windows 10)
PrinterService MediaSizeNmaeのリスト
EPSON PX-1700F 100.0 148.0 : japanese-postcard(48)
98.0 148.0 : 洋形3号封筒 98 x 148 mm(104)
Canon MP493 series Printer 100.0 148.0 : japanese-postcard(48)
Canon Inkjet iP9910 100.0 148.0 : japanese-postcard(48)

 Linuxの場合です。どういうわけかMP493に同じものが3つ出てきます。

プリンタがサポートする用紙(Linux)
PrinterService MediaSizeNmaeのリスト
Canon_MP493_series 100.0 148.0 : japanese-postcard(48)
100.0 148.0 : japanese-postcard(48)
100.0 148.0 : japanese-postcard(48)
EPSON_EPSON_PX-1700F 100.0 148.0 : japanese-postcard(48)
98.002 147.99 : Envelope 98 x 148 mm(891)

 japanese-postcardはもともとのMediaSizeNameに名前も値も定義されているので、OSやプリンタが異なってもgetValue()の値は(48)と同一になると考えられます。

A3の場合

 Windows 10です。Canon MP493 はA4までのプリンタですが、A3に名乗りを上げています。これではA3非対応とできません。

プリンタがサポートする用紙(Windows 10)
PrinterService MediaSizeNmaeのリスト
EPSON PX-1700F 297.0 420.0 : iso-a3(3)
Canon MP493 series Printer 297.0 420.0 : iso-a3(3)
Canon Inkjet iP9910 297.0 420.0 : iso-a3(3)
297.0 420.0 : ファインアート A3(128)

 Linuxの場合です。MP493は対応しないと分かります。

プリンタがサポートする用紙(Linux)
PrinterService MediaSizeNmaeのリスト
Canon_MP493_series  
EPSON_EPSON_PX-1700F 297.0 420.0 : iso-a3(3)

A4の場合

 Windows 10です。ユーザー定義というのは、A4にしておいて、余白を大きくとって調整するという作戦なのかもしれません。

プリンタがサポートする用紙(Windows 10)
PrinterService MediaSizeNmaeのリスト
EPSON PX-1700F 210.0 297.0 : iso-a4(4)
210.0 297.0 : ユーザー定義サイズ(67)
Canon MP493 series Printer 210.0 297.0 : iso-a4(4)
210.0 297.0 : ユーザー定義用紙...(122)
Canon Inkjet iP9910 210.0 297.0 : iso-a4(4)
210.0 297.0 : ファインアート A4(127)
210.0 297.0 : ユーザー定義用紙...(122)

 Linuxです。単純に1つずつです。

プリンタがサポートする用紙(Linux)
PrinterService MediaSizeNmaeのリスト
Canon_MP493_series 210.0 297.0 : iso-a4(4)
EPSON_EPSON_PX-1700F 210.0 297.0 : iso-a4(4)

困った。印刷できる封筒は意外に少ない

 さらに長形3号以外のJIS封筒についてもMediaSizeNameを取得できるか「SupportedValuesTest.java」を使って確認してみました。ところが、多くの封筒でうまく行きませんでした。そこで、JavaのMediaSizeに登録されたJIS封筒24種について、getSupportedAttributeValues()メソッドでMediaSizeNameが得られるかを調べて表にしました。

 長形、角形、洋形に分けてまとめています。Win/Linの欄にP,M,Iなどが書かれているものが、幅×高からMediaSizeNameが取得できたものです。

 表の詳しい説明は以下のとおりです。

  • 名前
    JIS,旧JIS,および類する封筒の名前。
  • 幅×高
    用紙のサイズ。単位はmm。Javaの仕様に従い短辺を幅にしてあります。
  • 投入書類・用途
    どのような大きさかの目安にするため投入できる用紙を折り方と共に紹介します。
    ISO A3 297×420(mm)、ISO A4 210×297(mm)、ISO A5 148×210(mm)、
    JIS B4 257×364(mm)、JIS B5 182×257(mm)、JIS B6 128×182(mm)。
  • 規格
    "JIS"が現行JIS(JIS S 5502:2014)に規定されているもの。
    現在のJISにあるのは18種だけです。旧JISについては一次情報を調べていないので改定の時期は正確ではありません。
  • 登録MS
    JavaのMediaSizeに登録されている名前。
  • Win/Lin
    幅×高からMediaSizeNameを取得できるかどうか。WinはWindows 10上、LinはLinux上。
    取得できたプリンタをP,M,Iの英字一文字で表してあります。
    P:PX-1700F、M:MP-493、I:iP9900(Winのみ)、-:対応しない。
  • 登録MSN
    MediaSizeNameに定数フィールド値が用意されているものの名前です。
    プリンタから得られるMediaSizeNameではなくjavax.print.attribute.standardにある近いサイズのMediaSizeNameです(≒は近い、=は同等)。
    ここに名前が入っていても「Win/Lin」の欄にPMIのどれかがない場合は、印刷に指定できません。

 そもそも、封筒への印刷が必要かどうかや、OSやプリンタのドライバの違いもあり個別に対応すべき事態になるので、調査の方法も書いておきます。封筒への印刷が必要な場合に参考になるように願っています。

長形

 長形は幅に対して2倍以上の高さがある封筒とされています。

長形のJIS封筒の一覧
名前 幅×高 投入書類­・用途 規格 登録MS Win Lix 登録MSN
長形 1号 142×332 A3横3折 旧JIS­(〜1964年版) CHOU_1 --- --  
長形 2号 119×277 B4横4折・A4横3折 JIS CHOU_2 --- -- ≒NA_NUMBER­_12­_ENVELOPE­(2.4)
長形 3号 120×235 A4横3折・定形最大 JIS CHOU_3 PMI PM  
長形 30号 92×235 A4横4折   CHOU_30 --- --  
長形 4号 90×205 B5横4折 JIS CHOU_4 PMI PM  
長形 40号 90×225 A4横4折 JIS CHOU_40 --- --  
長形 5号 90×185 B5横4折 旧JIS(〜1993年版)   --- --  
長形 6号 110×220 A4横3折・長3返信 JIS(2010年版〜)   -MI -M =ISO_DESIG­NATED_LONG

 getSupportedAttributeValues()メソッドでMediaSizeNameが得られるものはWin/Linの欄にP,M,Iなどが書かれているものです。

角形

 角形は幅に対して2倍以下の高さの(細長くない)封筒とされています。

角形のJIS封筒の一覧
名前 幅×高 投入書類­・用途 規格 登録MS Win Lix 登録MSN
角形 0号 *287×382 B4判 JIS KAKU_0 --- --  
角形 1号 *270×382 B4判 旧JIS(〜1964年版) KAKU_1 --- --  
角形 2号 *240×332 A4判 JIS KAKU_2 P-- P-  
角形20号 *229×324 A4判 JIS KAKU_20 --- -- =ISO_C4
角形 3号 *216×277 B5判・­書籍雑誌 JIS KAKU_3 --- --  
角形 4号 197×267 B5判 JIS KAKU_4 --- --  
角形 5号 190×240 A5判・­書籍雑誌 JIS KAKU_5 --- --  
角形 6号 162×229 A5判 JIS KAKU_6 --- -M =ISO_C5
角形 7号 142×205 B6判・­B4縦横4折 JIS KAKU_7 --- --  
角形 8号 119×197 給料 JIS KAKU_8 --- --  
角形A4号 *228×312 A4判   KAKU_A4 --- --  

 getSupportedAttributeValues()メソッドでMediaSizeNameが得られるものはWin/Linの欄にP,M,Iなどが書かれているものです。極めて少なくなっています。

 幅×高の幅に*印がついて太字になっているのは、A4プリンタでは入らないものです。

洋形

 洋形は長辺側に開口部がある封筒とされています。

洋形のJIS封筒の一覧
名前 幅×高 投入書類­・用途 規格 登録MS Win Lix 登録MSN
洋形 1号 120×176 カード,­招待状,­案内状 JIS YOU_1 P-- PM  
洋形 2号 114×162 A4縦横4折,­はがき JIS YOU_2 P-- PM =ISO_C6
洋形 3号 98×148 B5縦横4折 旧JIS(〜1993年版) YOU_3 P-- P-  
洋形 4号 105×235 A4横3折,­エアメール JIS YOU_4 PMI PM  
洋形 5号 95×217 A5縦2折 旧JIS(〜1993年版) YOU_5 --- --  
洋形 6号 98× 190 B5横3折 JIS YOU_6 -MI -M ≒MONARCH_ENVE­LOPE(0.5)
洋形 7号 92×165 A5横3折 旧JIS(〜1993年版) YOU_7 --- -- ≒PERSONAL_ENVE­LOPE(0.1)

 getSupportedAttributeValues()メソッドでMediaSizeNameが得られるものはWin/Linの欄にP,M,Iなどが書かれているものです。P:PX-1700F、M:MP-493、I:iP9900(Winのみ)ですが、洋形はプリンタにより対応に差がある封筒です。

次のページ
(3)用紙サイズからプリンタを検索・選択するプログラムを作る

この記事は参考になりましたか?

Javaの標準機能だけで実現する帳票印刷連載記事一覧

もっと読む

この記事の著者

安達 順一(アダチ ジュンイチ)

私立高校に理科・情報の教員として勤めていました。Linuxサーバー/クライアントの授業システムを作り、移動プロファイルで運用していました。教員用にもLinuxサーバーを用意し成績処理プログラムを書きました。情報の学校設定科目ではウェブページ制作とjavaのプログラミングの初歩の授業を作りました。情報...

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/11671 2020/06/22 11:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー