26

私はしばらくの間、標準のJava Printライブラリを使用して、特定の属性を持つファイル(具体的には、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が無視されると実際に記載されています。 ここに表示されているソースコードは、これが真であることを示しています。属性は渡され、完全に無視されます。

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

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が設定しただけで、完全な状態になることはありませんか?もしそうなら、代替手段はありますか?

4

5 に答える 5

10

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

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

いくつかの提案:

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

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

于 2013-07-18T21:48:42.597 に答える
1

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

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

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

-RAM

于 2015-01-22T18:40:23.947 に答える
1

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
于 2017-09-06T18:56:44.123 に答える
1

プリンタトレイの秘訣は、Media.class使用を繰り返しgetSupportedAttributeValues(...)、人間が読める名前と一致させ、その特定の値を選択することです。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);
于 2019-07-05T20:50:26.760 に答える