Mencetak Dengan Java Print Service API


Saya mendapat pertanyaan dari seorang teman yang bekerja sebagai freelancer:  bagaimana cara mencetak ke printer dengan nama tertentu di Java?   Pada kasusnya, terdapat tiga printer dengan nama berbeda dimana masing-masing printer memiliki ‘tugas‘-nya sendiri. Bagaimana caranya agar proses percetakan ke masing-masing printer berlangsung otomatis (secara programatis) ke printer yang telah ditentukan, tanpa memunculkan dialog percetakan (sehingga pengguna tidak perlu memilih printer secara manual)?

Seperti yang diketahui, cara mudah untuk mencetak ke printer di platform Java adalah dengan memakai Java 2D Printing API.   Developer bahkan bisa mencetak isi sebuah komponen di layar dengan memanggil method print() atau printAll().   Akan tetapi, pada kasus tertentu, developer menginginkan kendali yang lebih jauh lagi.   Untuk itu, saya dapat menggunakan Java Print Service (JPS) API.

Pada JPS, sebuah instance dari PrintService mewakili sebuah printer.   Untuk mendapatkan PrintService yang ada, saya dapat memakai class PrintServiceLookup.   Format yang didukung oleh sebuah PrintService diwakili oleh class DocFlavor.   Percetakan hanya dapat dilakukan ke printer yang mendukung DocFlavor dari dokumen yang akan dicetak.

Sebagai contoh, berikut ini adalah kode program yang menampilkan nama dan DocFlavor yang didukung oleh printer default.  Pada platform Windows, printer default adalah printer yang memiliki tanda centang bila dilihat di Control Panel, Devices and Printers:

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;

public class Main {

    public static void main(String[] args) {
        System.out.println("Menampilkan informasi untuk printer default:");
        PrintService service = PrintServiceLookup.lookupDefaultPrintService();
        System.out.printf("Nama printer: %s\n", service.getName());
        System.out.println("Format yang didukung:");
        for (DocFlavor format: service.getSupportedDocFlavors()) {
            System.out.println(format);
        }
    }
}

Berikut ini adalah contoh dari output kode program di atas:

Menampilkan informasi untuk printer default:
Nama printer: NAMA_PRINTER_1
Format yang didukung:
image/gif; class="[B"
image/gif; class="java.io.InputStream"
image/gif; class="java.net.URL"
image/jpeg; class="[B"
image/jpeg; class="java.io.InputStream"
image/jpeg; class="java.net.URL"
image/png; class="[B"
image/png; class="java.io.InputStream"
image/png; class="java.net.URL"
application/x-java-jvm-local-objectref; class="java.awt.print.Pageable"
application/x-java-jvm-local-objectref; class="java.awt.print.Printable"
application/octet-stream; class="[B"
application/octet-stream; class="java.net.URL"
application/octet-stream; class="java.io.InputStream"

MIME application/x-java-jvm-local-objectref adalah penanda untuk service-formatted print data dimana JPS akan menentukan sendiri format yang akan dicetak.   Bila memakai MIME ini, maka developer harus melewatkan object yang men-implementasi-kan class/interface yang tertera.   Sebagai contoh, pada output di atas, saya dapat melewatkan sebuah instance yang meng-implementasi-kan salah satu dari interface Pageable atau Printable.

MIME application/octet-stream adalah penanda untuk autosense print data.   Bila memakai MIME jenis ini, maka printer akan menentukan sendiri format dokumen yang akan dicetak.   Nilai yang ditunjukkan pada ‘class=’ adalah class yang dapat dipakai untuk mewakili data. Sebagai contoh, bila memakai application/octet-stream, berdasarkan output di atas, saya dapat melewatkan data salah satu bentuk berikut ini: byte array, instance dari java.net.URL atau instance dari java.io.InputStream.

Pada kode program sebelumnya, saya mengambil informasi dari printer default.   Bagaimana bila saya ingin mengambil informasi dari seluruh printer yang ter-install di komputer ini?   Saya dapat menggunakan kode program seperti berikut ini:

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;

public class Main {

    public static void main(String[] args) {
        System.out.println("\nMenampilkan informasi untuk seluruh printer:");
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, null);
        for (PrintService service: services) {
            System.out.printf("\nNama printer: %s\n", service.getName());
            System.out.println("Format yang didukung:");
            for (DocFlavor format: service.getSupportedDocFlavors()) {
                System.out.println(format);
            }
        }
    }
}

Berikut ini adalah contoh output dari kode program di atas:

Menampilkan informasi untuk seluruh printer:

Nama printer: NAMA_PRINTER_2
Format yang didukung:
image/gif; class="[B"
image/gif; class="java.io.InputStream"
image/gif; class="java.net.URL"
image/jpeg; class="[B"
image/jpeg; class="java.io.InputStream"
image/jpeg; class="java.net.URL"
image/png; class="[B"
image/png; class="java.io.InputStream"
image/png; class="java.net.URL"
application/x-java-jvm-local-objectref; class="java.awt.print.Pageable"
application/x-java-jvm-local-objectref; class="java.awt.print.Printable"
application/octet-stream; class="[B"
application/octet-stream; class="java.net.URL"
application/octet-stream; class="java.io.InputStream"

Nama printer: NAMA_PRINTER_3
Format yang didukung:
image/gif; class="[B"
image/gif; class="java.io.InputStream"
image/gif; class="java.net.URL"
image/jpeg; class="[B"
image/jpeg; class="java.io.InputStream"
image/jpeg; class="java.net.URL"
image/png; class="[B"
image/png; class="java.io.InputStream"
image/png; class="java.net.URL"
application/x-java-jvm-local-objectref; class="java.awt.print.Pageable"
application/x-java-jvm-local-objectref; class="java.awt.print.Printable"
application/octet-stream; class="[B"
application/octet-stream; class="java.net.URL"
application/octet-stream; class="java.io.InputStream"

Nama printer: NAMA_PRINTER_1
Format yang didukung:
image/gif; class="[B"
image/gif; class="java.io.InputStream"
image/gif; class="java.net.URL"
image/jpeg; class="[B"
image/jpeg; class="java.io.InputStream"
image/jpeg; class="java.net.URL"
image/png; class="[B"
image/png; class="java.io.InputStream"
image/png; class="java.net.URL"
application/x-java-jvm-local-objectref; class="java.awt.print.Pageable"
application/x-java-jvm-local-objectref; class="java.awt.print.Printable"
application/octet-stream; class="[B"
application/octet-stream; class="java.net.URL"
application/octet-stream; class="java.io.InputStream"

Bagaimana bila saya hanya ingin mencari printer dengan nama tertentu saja?   Saya dapat melewatkan sebuah AttributeSet pada saat memanggil lookupPrinterServices() seperti yang terlihat pada kode program berikut ini:

import javax.print.DocFlavor;
import javax.print.PrintService;
import javax.print.PrintServiceLookup;
import javax.print.attribute.HashAttributeSet;
import javax.print.attribute.standard.PrinterName;

public class Main {

    public static void main(String[] args) {

        HashAttributeSet attributes = new HashAttributeSet();
        attributes.add(new PrinterName("NAMA_PRINTER_1", null));

        System.out.println("\nMenampilkan printer:");
        PrintService[] services = PrintServiceLookup.lookupPrintServices(null, attributes);
        for (PrintService service: services) {
            System.out.printf("\nNama printer: %s\n", service.getName());
            System.out.println("Format yang didukung:");
            for (DocFlavor format: service.getSupportedDocFlavors()) {
                System.out.println(format);
            }
        }

    }
}

Setelah mendapatkan PrintService yang diinginkan, bagaimana cara mencetak ke printer tersebut?   Untuk mencetak saya harus menghasilkan sebuah DocPrintJob dari PrintService.   Object DocPrintJob ini dapat dipakai untuk mencetak dokumen yang diwakili dengan sebuah Doc.   Proses mencetak akan dimulai setelah saya memanggil method print() dari DocPrintJob tersebut.

Saat saya mencoba mencetak dengan mengirim data langsung ke printer (auto sense),  dimana saya mengirimkan deretan byte karakter ASCII,  saya memperoleh pesan kesalahan ‘Error – printing’ di tampilan queue percetakan Windows.   Hal ini karena saya mencetak ke sebuah printer deskjet ekonomis yang memakai bahasa printer HP Lightweight Imaging Device Interface Language (LIDIL).   Bahasa printer ini sering dipakai oleh printer Hewlett-Packard (HP) ekonomis yang tidak mendukung bahasa Printer Command Language (PCL).   Tidak seperti PCL yang menerima input berupa tulisan teks, LIDIL membutuhkan deretan byte khusus untuk menggambar titik (raster).   LIDIL tidak mendukung perintah berupa teks ASCII.   Oleh sebab itu, saat saya mengirim tulisan teks secara langsung ke printer, saya akan memperoleh pesan ‘Error – printing’ dari printer karena perintah tersebut bukan perintah LIDIL yang valid.

Cara yang lebih aman adalah mencetak tulisan dengan menggunakan service-formatted print data:

import ...

public class Main {

    public static void main(String[] args) {

        HashAttributeSet attributes = new HashAttributeSet();
        attributes.add(new PrinterName("NAMA_PRINTER_1", null));
        DocFlavor format = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(format, attributes);
        if (services.length > 0) {
            Doc doc = new SimpleDoc(new Printable() {

                @Override
                public int print(Graphics g, PageFormat pageFormat, int pageIndex) throws PrinterException {
                    if (pageIndex==0) {
                        int x = (int) pageFormat.getImageableX();
                        int y = (int) pageFormat.getImageableY();
                        int width = (int) pageFormat.getImageableWidth();
                        int height = (int) pageFormat.getImageableHeight();
                        g.drawRect(x, y, width, height);
                        g.drawString("Selamat datang di TheSolidSnake", x+5, y+20);
                        return PAGE_EXISTS;
                    } else {
                        return NO_SUCH_PAGE;
                    }
                }

            }, format, null);
            try {
                services[0].createPrintJob().print(doc, null);
            } catch (PrintException ex) {
                ex.printStackTrace();
            }
        } else {
            System.out.println("Printer tidak ditemukan!");
        }
    }
}

Bila kode program di atas dijalankan, printer dengan nama “NAMA_PRINTER_1” akan mencetak kertas dengan border dan tulisan ‘Selamat datang di TheSolidSnake’.   Percetakan akan langsung dimulai pada saat itu juga tanpa memunculkan kotak dialog.

Saya juga dapat mencetak komponen GUI dengan cara seperti ini.   Sebagai contoh, kode program berikut ini akan mencetak isi dari JTextArea ke printer dengan nama “NAMA_PRINTER_1”:

import ...

public class Main extends JFrame implements ActionListener {

    private JTextArea txtInput;
    private JButton btnCetak;

    public Main() {
        super("Latihan Mencetak");

        txtInput = new JTextArea();
        btnCetak = new JButton("Cetak Ke Printer Dengan Nama 'NAMA_PRINTER_1'");
        btnCetak.addActionListener(this);

        setLayout(new BorderLayout());
        add(new JScrollPane(txtInput), BorderLayout.CENTER);
        add(btnCetak, BorderLayout.PAGE_END);
    }

    public static void main(String[] args) {

        SwingUtilities.invokeLater(new Runnable() {

            @Override
            public void run() {
                JFrame f = new Main();
                f.pack();
                f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
                f.setVisible(true);
            }

        });
    }

    @Override
    public void actionPerformed(ActionEvent e) {
        HashAttributeSet attributes = new HashAttributeSet();
        attributes.add(new PrinterName("NAMA_PRINTER_1", null));
        DocFlavor format = DocFlavor.SERVICE_FORMATTED.PRINTABLE;
        PrintService[] services = PrintServiceLookup.lookupPrintServices(format, attributes);
        if (services.length > 0) {
            try {
                txtInput.print(null, null, false, services[0], null, false);
            } catch (PrinterException ex) {
                ex.printStackTrace();
            }
        } else {
            System.out.println("Printer tidak ditemukan!");
        }

    }
}

Tampilan kode program di atas akan terlihat seperti pada gambar berikut ini:

Tampilan Program

Tampilan Program

Perihal Solid Snake
I'm nothing...

Apa komentar Anda?

Please log in using one of these methods to post your comment:

Logo WordPress.com

You are commenting using your WordPress.com account. Logout / Ubah )

Gambar Twitter

You are commenting using your Twitter account. Logout / Ubah )

Foto Facebook

You are commenting using your Facebook account. Logout / Ubah )

Foto Google+

You are commenting using your Google+ account. Logout / Ubah )

Connecting to %s

%d blogger menyukai ini: