web-dev-qa-db-ja.com

javax.printライブラリを使用した属性(トレイコントロール、両面印刷など)での印刷

私はしばらくの間、standard Java Print libraryを使用してファイルを印刷する方法を決定しようとしてきました-具体的には、PDFドキュメント-特定の属性-具体的には、特定のトレイまたはデュプレックスを使用します。

これをどのように行うべきかについてのドキュメントはたくさんあります。実際、私はこれらの方法を調査して試しました。典型的な方法は次のようなものです。

public static void main (String [] args) {
    try {

        PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);

        //Acquire Printer
        PrintService printer = null;
        for (PrintService serv: pservices) {
            System.out.println(serv.toString());
            if (serv.getName().equals("PRINTER_NAME_BLAH")) {
                printer = serv;
            }
        }

        if (printer != null) {
            System.out.println("Found!");


            //Open File
            FileInputStream fis = new FileInputStream("FILENAME_BLAH_BLAH.pdf");

            //Create Doc out of file, autosense filetype
            Doc pdfDoc = new SimpleDoc(fis, DocFlavor.INPUT_STREAM.AUTOSENSE, null);

            //Create job for printer
            DocPrintJob printJob = printer.createPrintJob();

            //Create AttributeSet
            PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();

            //Add MediaTray to AttributeSet
            pset.add(MediaTray.TOP);

            //Add Duplex Option to AttributeSet
            pset.add(Sides.DUPLEX);

            //Print using Doc and Attributes
            printJob.print(pdfDoc, pset);

            //Close File
            fis.close();

        }

    }
    catch (Throwable t) {
        t.printStackTrace();
    }
}

要するに、あなたは次のことをします

  1. プリンタを探す
  2. PrinterJobを作成する
  3. AttributeSetを作成する
  4. トレイやデュプレックスなどの属性をAttributeSetに追加します
  5. AttributeSetを使用してプリンタージョブでprintを呼び出します

ここでの問題は、これを行うための文書化された方法であり、いくつかのチュートリアルから私が見つけたものであるにもかかわらず、この方法は...が機能しないことです。覚えておいてください、それはあまり説明的ではないように聞こえますが、私に聞いてください。 私はそれを軽くは言いません.。

PrinterJobの公式ドキュメント 実際には、デフォルトの実装ではAttributeSetが無視されると記載されています。 ここに表示されているソースコード これがtrueであることを示しています-属性は渡され、完全に無視されます。

どうやら、特定のプリンタとその機能に基づいている可能性のある、クラスのある種の拡張バージョンが必要ですか?私はそのような機能を教えてくれるいくつかのテストコードを書こうとしました-私たちはオフィスに多種多様なプリンターをセットアップしました、大小、シンプルまたはベルとホイッスルでいっぱいです-疑似のためだけに私のコンピューター上のいくつかのドライバーは言うまでもありません-ドキュメントを作成し、ハードウェアを使用せずにプリンターをシミュレートするプリンタードライバー。テストコードは次のとおりです。

public static void main (String [] args) {

    PrintService[] pservices = PrintServiceLookup.lookupPrintServices(null, null);

    for (PrintService serv: pservices) {
        System.out.println(serv.toString());

        printFunctionality(serv, "Trays", MediaTray.class);
        printFunctionality(serv, "Copies", Copies.class);
        printFunctionality(serv, "Print Quality", PrintQuality.class);
        printFunctionality(serv, "Color", ColorSupported.class);
        printFunctionality(serv, "Media Size", MediaSize.class);
        printFunctionality(serv, "Accepting Jobs", PrinterIsAcceptingJobs.class);
    }
}

private static void printFunctionality(PrintService serv, String attrName, Class<? extends Attribute> attr) {
    boolean isSupported = serv.isAttributeCategorySupported(attr);
    System.out.println("    " + attrName + ": " + (isSupported ? "Y" : "N"));
}

私が見つけた結果は、例外なく、すべてのプリンターが「コピー」がサポートされていることを返し、他のすべての属性はサポートされていないことでした。さらに、それがどれほど信じがたいように思われるかにかかわらず、すべてのプリンターの機能は同一でした。

避けられない質問は多層的です:登録された方法で属性を送信するにはどうすればよいですか?さらに、プリンタの機能を適切に検出するにはどうすればよいですか?実際、PrinterJobクラスは実際に使用可能な方法で拡張されているのでしょうか、それとも属性は常に無視されているのでしょうか。

インターネット全体で見つけた例は、後者の質問に対する答えが「いいえ、常に無視されます」であることを示唆しているようです。これは私にはばかげているようです(ただし、数百ページをふるいにかけると、ますます信頼できるようになります)。 このコードは、Sunがセットアップしただけで、完全な状態になるまで動作しませんでしたか?もしそうなら、代替手段はありますか?

26
Southpaw Hare

そのため、私たちは必然的に、直接ではなく、さまざまなトレイにさまざまな設定で印刷する方法を見つけました。私たち属性を送信することは不可能であることがわかりました printJob.printメソッドを介して、そしてそれだけは変わっていません。ただし、印刷ジョブの名前を設定してから、低レベルのPerlスクリプトで印刷ジョブをインターセプトする、名前を解析し、そこでトレイと両面印刷の設定を行うことができました。これは極端なハックですが、機能します。 Javaプリンタ属性が機能しないであることは依然として真実であり、それらを設定する場合は別の方法を見つける必要がありますになります。

6
Southpaw Hare

問題は、Java print APIが世界間の架け橋であるということです。プリンターメーカーはJVMのドライバーをリリースしていません。彼らは、Windows、Macintoshのドライバーをリリースしており、誰かが1つ以上の* nixプラットフォームで動作する特定のプリンター。

それに伴い、いくつかのホストシステムのJVM内で実行されているJavaコードが付属しています。プリンター機能の照会を開始するときは、プリンターとは話していません。ブリッジクラスと話しているのです。 Java.awt.printでは、JVMにフックし、ホストオペレーティングシステムにフックし、特定のプリンターにインストールされている特定のドライバーにフックします。したがって、これが崩壊する可能性のある場所がいくつかあります...特定のJVMは、特定のジョブにこれらのパラメータを渡すことは言うまでもなく、プリンタ機能をクエリするためのAPIを完全に実装する場合としない場合があります。

いくつかの提案:

  1. java.awt.printの代わりとしてjavax.printクラスを調べてください-そこから印刷する運がもっとありました。
  2. プリンタに代替のプリントドライバを使用してみてください。特定のプリンタへの複数の名前付き接続を定義でき、それぞれに異なるドライバがあります。メーカー提供のドライバーをお持ちの場合は、より一般的なドライバーをお試しください。一般的なドライバーをお持ちの場合は、より具体的なドライバーをインストールしてみてください。
  3. プラットフォームの代替JVM実装でコードを実行する
10
ZachOfAllTrades

プリンタトレイの秘訣は、getSupportedAttributeValues(...)を使用してMedia.classを繰り返し処理し、人間が読める形式の名前と一致させて、その特定の値を選択することです。 Windows、MacOSで、いくつかのトレイ構成でテストされています。

String tray = "1";

// Handle human-readable names, see PRINTER_TRAY_ALIASES usage below for context.  Adjust as needed.
List<String> PRINTER_TRAY_ALIASES = Arrays.asList("", "Tray ", "Paper Cassette ");

// Get default printer
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();

// Attributes to be provided at print time
PrintRequestAttributeSet pset = new HashPrintRequestAttributeSet();

Media[] supported = printService.getSupportedAttributeValues(Media.class, null, null);
for(Media m : supported) {           
    for(String pta : PRINTER_TRAY_ALIASES) {
        // Matches "1", "Tray 1", or "Paper Cassette 1"
        if (m.toString().trim().equalsIgnoreCase(pta + tray)) {
            attributes.add(m);
            break;
        }
    }
}

// Print, etc
// printJob.print(pdfDoc, pset);
1
tresf

PDFを印刷するための同様の要件があり、特定のトレイにいくつかのページを送信し、ドキュメントをホチキス止めしたいと考えていました。 Javaコード+ゴーストスクリプトの組み合わせを使用しました。最初にPDFをゴーストスクリプトに変換し、次にPJL(印刷ジョブ言語)コマンドをゴーストスクリプトファイルに追加してトレイを選択し、ドキュメントをホチキス止めし、編集したゴーストスクリプトファイルをプリンタに送信します。

これはJavaで書かれた完全な例です

http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-Java-how.html

-羊

1
Reddymails

Javafxトレイの外観は次のとおりです。トレイの名前を変更するだけで、使用可能なすべてのトレイが印刷されます。

private void printImage(Node node) {
    PrinterJob job = PrinterJob.createPrinterJob();
    if (job != null) {
        JobSettings js = job.getJobSettings();
        PaperSource papersource = js.getPaperSource();
        System.out.println("PaperSource=" + papersource);
        PrinterAttributes pa = printer.getPrinterAttributes();
        Set<PaperSource> s = pa.getSupportedPaperSources();
        System.out.println("# of papersources=" + s.size());
        if (s != null) {
            for (PaperSource newPaperSource : s) {
                System.out.println("newpapersource= " + newPaperSource);
                //Here is where you would put the tray name that is appropriate
                //in the contains section
                if(newPaperSource.toString().contains("Tray 2"))
                    js.setPaperSource(newPaperSource);
            }
        }
        job.getJobSettings().setJobName("Whatever");
        ObjectProperty<PaperSource> sources = job.getJobSettings().paperSourceProperty();
        System.out.println(sources.toString());
        boolean success = job.printPage(node);
        if (success) {
            System.out.println("PRINTING FINISHED");
            job.endJob();
            //Stage mainStage = (Stage) root.getScene().getWindow();
            //mainStage.close();
        }
    }
}

これが私の出力です:

PaperSource=Paper source : Automatic
# of papersources=6
newpapersource= Paper source :
newpapersource= Paper source :  Manual Feed in Tray 1
newpapersource= Paper source :  Printer auto select
newpapersource= Paper source :  Tray 1
newpapersource= Paper source :  Tray 2
newpapersource= Paper source : Form-Source
ObjectProperty [bean:  Collation = UNCOLLATED
 Copies = 1
 Sides = ONE_SIDED
 JobName = Whatever
 Page ranges = null
 Print color = COLOR
 Print quality = NORMAL
 Print resolution = Feed res=600dpi. Cross Feed res=600dpi.
 Paper source = Paper source :  Tray 2
 Page layout = Paper=Paper: Letter size=8.5x11.0 INCH Orient=PORTRAIT leftMargin=54.0 rightMargin=54.0 topMargin=54.0 bottomMargin=54.0, name: paperSource, value: Paper source :  Tray 2]
PRINTING FINISHED
1
Matt