第1章: `javax.print.attribute`とは? – Java印刷APIの心臓部
Javaアプリケーションから印刷機能を利用する場合、Java Print Service (JPS) API を使用するのが標準的な方法です。このJPSの中核をなし、印刷の挙動を細かく制御するための重要な仕組みが、javax.print.attributeパッケージによって提供されています。
簡単に言えば、このパッケージは「何を」「どのように」印刷するかという指示(処理命令)を、標準化された「属性」という単位で管理するためのクラスとインターフェースの集まりです。
プリンタはメーカーや機種によってサポートする機能が多岐にわたります。両面印刷、カラー印刷、ステープル(ホチキス止め)、特定の給紙トレイの選択など、その能力は様々です。これらの違いをアプリケーション側で吸収し、統一的な方法でプリンタに指示を出すために、「属性ベース」の設計が採用されました。
クライアント(Javaアプリケーション)は、印刷したいデータとは別に、「3部印刷してほしい」「A4用紙に、横向きで印刷してほしい」といった要求を属性のセットとして作成し、印刷データと一緒に印刷サービスへ送ります。これにより、コードの再利用性が高まり、異なるプリンタに対しても柔軟に対応できるプログラムを記述することが可能になります。
javax.print.attributeパッケージは、Java 2 Platform, Standard Edition, v 1.4 (J2SE 1.4) で導入されたJava Print Service APIの一部です。これ以降、Javaの標準的な印刷機能として利用され続けています。
第2章: 基本となるインターフェース群
javax.print.attributeパッケージを理解する上で、まず押さえておくべきは中心的な役割を担ういくつかのインターフェースです。個々の属性クラスは、これらのインターフェースを実装することで、その役割や性質を定義しています。
1. `Attribute` インターフェース
すべての印刷属性の基礎となるのがAttributeインターフェースです。これは、あるクラスが印刷属性であることを示すマーカーとしての役割を持ちます。このインターフェースが実装するメソッドは以下の2つです。
<strong>getCategory()</strong>: 属性の「カテゴリ」をClassオブジェクトとして返します。カテゴリは、その属性がどのような種類のものか(例:部数、印刷品質)を識別するために使われます。通常、属性クラス自体が自身のカテゴリとなります。<strong>getName()</strong>: 属性の公式な名前を文字列で返します。この名前は、国際標準であるIPP (Internet Printing Protocol) の属性名と一致するように定められています。
2. `AttributeSet` インターフェース
AttributeSetは、その名の通りAttributeオブジェクトのコレクション(集合)を表現するインターフェースです。キーとして属性のカテゴリ(Classオブジェクト)、値として属性のインスタンス(Attributeオブジェクト)を持つマップのような構造をしています。これにより、同じカテゴリの属性を複数保持することがないようになっています(例:部数というカテゴリの属性は一つしか持てない)。
主なメソッドには以下のようなものがあります。
<strong>add(Attribute attribute)</strong>: セットに属性を追加します。<strong>remove(Class<?> category)</strong>: 指定したカテゴリの属性を削除します。<strong>get(Class<?> category)</strong>: 指定したカテゴリの属性を取得します。<strong>containsKey(Class<?> category)</strong>: 指定したカテゴリの属性が含まれているか確認します。
このAttributeSetインターフェースをさらに特化させた、以下の4つの重要なサブインターフェースが存在します。これらは、印刷プロセスのどの段階で使われる属性のセットなのかを明確に区別するためのものです。
| サブインターフェース | 対応する属性マーカー | 役割と使われる場面 |
|---|---|---|
<strong>DocAttributeSet</strong> |
DocAttribute |
個々のドキュメントに適用される属性をまとめます。例えば、複数ドキュメントを一度に印刷する際、1つ目のドキュメントはA4、2つ目はB5といった指定が可能です。 |
<strong>PrintRequestAttributeSet</strong> |
PrintRequestAttribute |
印刷ジョブ全体に対する要求設定をまとめます。部数、両面印刷、ジョブ名など、ジョブ全体に関わる設定がこれにあたります。最もよく使われる属性セットです。 |
<strong>PrintJobAttributeSet</strong> |
PrintJobAttribute |
印刷ジョブの現在の状態を報告するための属性をまとめます。ジョブが印刷中か、完了したか、エラーが発生したかなどのステータス情報が含まれます。 |
<strong>PrintServiceAttributeSet</strong> |
PrintServiceAttribute |
プリンタ(印刷サービス)自体の状態や情報を示す属性をまとめます。プリンタ名、待機中のジョブ数、用紙切れなどの情報が含まれます。 |
これらのセットは、HashAttributeSetという具象クラスや、それぞれのセットに対応するHashDocAttributeSet、HashPrintRequestAttributeSetなどを用いてインスタンス化するのが一般的です。
第3章: `javax.print.attribute.standard`パッケージの主要な属性クラス
JPSでは、一般的に使われる印刷属性がjavax.print.attribute.standardパッケージ内に標準クラスとしてあらかじめ定義されています。これにより、開発者は車輪の再発明をすることなく、標準化された方法で印刷設定を行えます。ここでは、特によく利用される代表的な属性クラスをいくつか紹介します。これらの多くは、PrintRequestAttributeインターフェースを実装しており、印刷要求時に使用されます。
Copies (部数)
印刷する部数を指定します。コンストラクタに整数値を渡してインスタンスを作成します。
// 3部印刷する設定
Copies copies = new Copies(3);
attributeSet.add(copies);
OrientationRequested (印刷の向き)
用紙の向き(縦、横など)を指定します。このクラスは列挙型(EnumSyntaxのサブクラス)であり、定義済みの静的フィールドを使用します。
OrientationRequested.PORTRAIT: 縦向きOrientationRequested.LANDSCAPE: 横向きOrientationRequested.REVERSE_LANDSCAPE: 逆向き横OrientationRequested.REVERSE_PORTRAIT: 逆向き縦
// 横向きに印刷する設定
attributeSet.add(OrientationRequested.LANDSCAPE);
Media (用紙)
印刷する用紙の種類やサイズ、給紙トレイを指定します。Mediaクラス自体は抽象クラスであり、実際にはそのサブクラスを使用します。
<strong>MediaSizeName</strong>: A4やLetterなど、標準的な用紙サイズを名前で指定します。MediaSizeName.ISO_A4やMediaSizeName.NA_LETTERのような静的フィールドが定義されています。<strong>MediaTray</strong>: プリンタの給紙トレイを指定します。MediaTray.MAIN,MediaTray.MANUAL,MediaTray.TOPなどがあります。
// 用紙サイズをA4に設定
attributeSet.add(MediaSizeName.ISO_A4);
// 給紙トレイを上段に設定
attributeSet.add(MediaTray.TOP);
特定の用紙サイズがプリンタでサポートされているかを確認し、動的にサイズを指定したい場合はMediaPrintableArea属性も関連してきます。
Sides (両面印刷)
片面印刷か両面印刷かを指定します。これも列挙型のクラスです。
Sides.ONE_SIDED: 片面印刷Sides.TWO_SIDED_LONG_EDGE: 両面印刷(長辺とじ)Sides.TWO_SIDED_SHORT_EDGE: 両面印刷(短辺とじ)
// 両面印刷(長辺とじ)を設定
attributeSet.add(Sides.TWO_SIDED_LONG_EDGE);
Chromaticity (カラー/モノクロ)
印刷をカラーで行うかモノクロで行うかを指定します。
Chromaticity.MONOCHROME: モノクロ印刷Chromaticity.COLOR: カラー印刷
// カラーで印刷する設定
attributeSet.add(Chromaticity.COLOR);
JobName (ジョブ名)
印刷キューに表示されるジョブの名前を指定します。デバッグや管理に役立ちます。コンストラクタに文字列とロケールを渡します。
// 印刷ジョブの名前を設定
JobName jobName = new JobName("MonthlyReport-2025-07", java.util.Locale.getDefault());
attributeSet.add(jobName);
PrintQuality (印刷品質)
印刷の品質を指定します。プリンタがこの機能をサポートしている必要があります。
PrintQuality.DRAFT: 下書き品質PrintQuality.NORMAL: 標準品質PrintQuality.HIGH: 高品質
// 高品質で印刷する設定
attributeSet.add(PrintQuality.HIGH);
Fidelity (忠実度)
これは少し特殊な属性で、FidelityクラスのFIDELITY_TRUEまたはFIDELITY_FALSEを設定します。FIDELITY_TRUEが設定されている場合、要求した属性(部数、両面など)のすべてをプリンタがサポートしていないと、印刷ジョブは失敗します。デフォルトはFIDELITY_FALSEで、サポートしていない属性は無視して、可能な範囲で印刷を試みます。
第4章: 実践!コードで見る`javax.print.attribute`の使い方
これまでに学んだ知識を組み合わせて、実際に印刷要求を行うコードを見ていきましょう。ここでは、テキストファイルをA4・横向き・2部で印刷する、というシナリオを想定します。
ステップ1: 印刷データの準備とDocFlavorの定義
まず、印刷するデータとその形式(フォーマット)を定義します。データ形式はDocFlavorクラスで表現されます。ここではプレーンテキストを扱います。
// 印刷するテキストデータ
String textToPrint = "Hello, Java Print Service! This is a test.";
// DocFlavorを定義 (プレーンテキスト、文字列表現)
DocFlavor flavor = DocFlavor.STRING.TEXT_PLAIN;
ステップ2: 印刷属性セット(PrintRequestAttributeSet)の作成
次に、PrintRequestAttributeSetのインスタンスを作成し、要求したい属性を追加していきます。実装クラスとしてHashPrintRequestAttributeSetを使用します。
// PrintRequestAttributeSetのインスタンス化
PrintRequestAttributeSet attributeSet = new HashPrintRequestAttributeSet();
// 属性を追加していく
// 1. 部数: 2部
attributeSet.add(new Copies(2));
// 2. 用紙サイズ: A4
attributeSet.add(MediaSizeName.ISO_A4);
// 3. 印刷の向き: 横向き
attributeSet.add(OrientationRequested.LANDSCAPE);
// 4. ジョブ名
attributeSet.add(new JobName("APITestJob", null));
ステップ3: 印刷サービスの検索
作成したデータ形式(DocFlavor)と属性セット(AttributeSet)をサポートするプリンタ(PrintService)を検索します。PrintServiceLookupクラスの静的メソッドを利用します。
// 上記のFlavorとAttributeSetをサポートするPrintServiceを検索
PrintService[] services = PrintServiceLookup.lookupPrintServices(flavor, attributeSet);
if (services.length == 0) {
System.err.println("利用可能なプリンタが見つかりません。");
// フォールバック: デフォルトプリンタを取得
PrintService defaultService = PrintServiceLookup.lookupDefaultPrintService();
if (defaultService == null) {
System.err.println("デフォルトプリンタも設定されていません。");
return;
}
// デフォルトプリンタを利用
print(defaultService, flavor, textToPrint, attributeSet);
} else {
// 見つかった最初のプリンタを利用
System.out.println("プリンタが見つかりました: " + services.getName());
print(services, flavor, textToPrint, attributeSet);
}
ステップ4: 印刷ジョブの作成と実行
最後に、PrintServiceからDocPrintJobを作成し、印刷データと属性をカプセル化したDocオブジェクトを渡してprintメソッドを呼び出します。
private static void print(PrintService service, DocFlavor flavor, String data, PrintRequestAttributeSet attributes) {
// DocPrintJobの作成
DocPrintJob job = service.createPrintJob();
// 印刷データをDocオブジェクトにカプセル化 (DocAttributeSetはnull)
Doc doc = new SimpleDoc(data, flavor, null);
try {
// 印刷の実行! PrintRequestAttributeSetを渡す
job.print(doc, attributes);
System.out.println("印刷ジョブを投入しました。");
// (オプション) ジョブの状態を監視
// job.addPrintJobListener(new PrintJobAdapter() { ... });
} catch (PrintException e) {
System.err.println("印刷中にエラーが発生しました。");
e.printStackTrace();
}
}
この一連の流れにより、指定した属性で印刷処理が実行されます。プリンタが要求された属性(例えば横向き印刷)をサポートしていない場合、デフォルトのFidelity設定(FIDELITY_FALSE)により、その属性は無視され、プリンタが実行可能な形で印刷されます。
第5章: 便利なユーティリティクラス: `AttributeSetUtilities`
javax.print.attributeパッケージには、AttributeSetを操作する上で便利な静的メソッドを提供するAttributeSetUtilitiesクラスが含まれています。このクラスを使うことで、より安全で堅牢なコードを書くことができます。
変更不可能なビューの作成
属性セットをメソッドの戻り値として返す場合など、外部から内容を変更されたくない場面があります。その際にunmodifiableSetメソッドが役立ちます。
AttributeSet originalSet = new HashPrintRequestAttributeSet();
originalSet.add(new Copies(1));
// 変更不可能なビューを作成
AttributeSet unmodifiableView = AttributeSetUtilities.unmodifiableSet(originalSet);
// このビューに対して変更操作を行うと、UnmodifiableSetExceptionがスローされる
try {
unmodifiableView.add(new Copies(2)); // ここで例外が発生
} catch (Exception e) {
System.out.println(e.getClass().getName() + "が発生しました!");
}
スレッドセーフなビューの作成
複数のスレッドから同じ属性セットにアクセスする可能性がある場合、排他制御を行わないと予期せぬ動作を引き起こす原因となります。synchronizedViewメソッドを使えば、簡単にスレッドセーフな属性セットのビューを生成できます。
AttributeSet originalSet = new HashPrintRequestAttributeSet();
// 同期されたビューを作成
AttributeSet synchronizedView = AttributeSetUtilities.synchronizedView(originalSet);
// このビューを介した操作はスレッドセーフになる
// 例: スレッドA
new Thread(() -> synchronizedView.add(new Copies(5))).start();
// 例: スレッドB
new Thread(() -> System.out.println(synchronizedView.get(Copies.class))).start();
生成されたビューを介したすべての操作は、ビューオブジェクト自体をロックとして同期されます。
これらのユーティリティは、APIの設計や、複雑なアプリケーションを構築する際に、AttributeSetの不変性やスレッドセーフティを保証する上で非常に強力なツールとなります。
まとめ
本記事では、Java Print Service APIの心臓部であるjavax.print.attributeパッケージについて、その基本的な概念から具体的な使い方までを詳細に解説しました。
属性ベースの印刷制御は、一見すると複雑に感じるかもしれません。しかし、その仕組みを一度理解すれば、多様なプリンタの機能を抽象化し、非常に柔軟で強力な印刷ソリューションをJavaアプリケーションに組み込むことができるようになります。
今回紹介した内容は、javax.print.attributeが持つ機能のほんの一部です。各プリンタが独自に提供するベンダー固有の属性を扱ったり、印刷ジョブのイベントを監視してより高度な制御を行ったりすることも可能です。
この記事を足がかりに、ぜひ公式のAPIドキュメントなどを参照し、Javaによる印刷機能のさらなる可能性を探求してみてください。