I have been trying to use a thermal-printer "Bixolon SRP-F310" and print some text using JAVA's PrintService. Printer is detected and there is no exception while calling the print function. I can see in the web interface of Cups that the print event is called. However the printer doesn't print and the error message "No pages found!" can be seen in the web-interface of Cups. Any help will be appreciated. I have included the screenshot of the Cups web-interface and the error logs.
import javax.print.*;
import java.util.Arrays;
import java.util.List;
public class Printer {
static Printer INSTANCE;
public static void main(String[] args) {
INSTANCE = new Printer();
List<PrintService> services = INSTANCE.getServicesByName("BIXOLON_SRP-F310");
if(services == null) {
throw new RuntimeException("No printer services available");
}
INSTANCE.printServices(services);
try {
INSTANCE.print(services.get(0), "Hello");
} catch (Exception e) {
e.printStackTrace();
}
}
public List<PrintService> getServicesByName(String serviceName) {
//Find printer service by name
AttributeSet aset = new HashAttributeSet();
aset.add(new PrinterName(serviceName, null));
return Arrays.asList(PrintServiceLookup.lookupPrintServices(null, aset));
}
public void print(PrintService service, String printData) throws Exception {
if(service == null) {
throw new Exception("Service is not valid");
}
if(printData == null) {
throw new Exception("Nothing to print");
}
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new Copies(1));
pras.add(new PrinterResolution(180,180,PrinterResolution.DPI));
DocPrintJob job = service.createPrintJob();
DocAttributeSet das = new HashDocAttributeSet();
das.add(new PrinterResolution(180,180,PrinterResolution.DPI));
byte[] desc = printData.getBytes();
Doc doc = new SimpleDoc(desc, DocFlavor.BYTE_ARRAY.AUTOSENSE, das);
try {
job.print(doc, pras);
} catch (Exception e) {
e.printStackTrace();
}
}
public void printServices(List<PrintService> services) {
System.out.println("Printer Services found:");
for (PrintService service : services) {
System.out.println("\t" + service);
}
}
}
Web Interface of Cups:
Error Logs:
http://pastebin.com/kYiKGsSn
Do the following steps and Hopefully your problem will be solved.
Check the IP of your printer if it's same which you are hitting through CUPs then fine otherwise you have to reset the IP.
Reset IP: Press the feed button of your thermal printer for 2-3 min a long print receipt will print with detail info about the printer.
Now just attache your printer with LAN cable to your PC and open the printer settings. Here you can reset the printer IP according to the manual of that particulate printer.
After setting the IP now try again from the server to hit on that thermal printer with new IP.
If your CUPS is installed properly then it will work and otherwise you have to check the CUPS.
Check all these things and let me know is that works or any error message.
I'm facing the very same problem as you did. You may try to setup your page size and format. Try to do that.
You can as well do a simple troubleshoot such as using another printer. If things goes OK, it is safe to assume that there's nothing wrong with your code, but the printer driver you are currently using might be causing the problem.
Related
I've been banging my head on this all day, read everything I can find, followed the JDK source around, no luck in finding out the gory details about HOW or WHERE java looks to obtain data on a midi device and determines what's what.
I'm trying to capture midi messages through my NI Audio 8 DJ MIDI IN port, but, java isn't "seeing" the MIDI IN port, only the out, which I have successfully used to send midi with. I also get the same results with an M-Audio USB UNO midi device: MidiSystem.getMidiDeviceInfo() only "sees" the output port.
I have verified the operation of the MIDI IN port with:
amidi -p hw:2,0 -d
and sending it some signals. Works fine.
getMaxTransmitters() returns zero.
MidiSystem.getMidiDeviceInfo() shows only one entry for both devices: Audio8DJ [hw:2,0] or Interface [hw:2,0]
The code below works fine for a Receiver and I think is only the bits I need to verify that getTransmitter() grabs the port, since it just works for the other and everything works fine, up I get a MidiUnavailableException / Transmitter not available exception.
I've even taken the getMaxReceivers() trap out because I was just trying to see if the device only offered up the one entry and sorted it out, but no.
public static Transmitter getMidiIn () {
if (midiIn == null){
devices = MidiSystem.getMidiDeviceInfo();
for(MidiDevice.Info info: devices){
System.out.println("device class " + info.getClass());
MidiDevice device;
try{
device = MidiSystem.getMidiDevice(info);
if (info.toString().equals("Audio8DJ [hw:2,0]")){
if (device.getMaxTransmitters() != 0){
try{
device.open();
System.out.println("max transmitters:" + device.getMaxTransmitters());
midiIn = device.getTransmitter();
System.out.println("Found a transmitter: "+ midiIn);
break;
} catch (Exception e){
e.printStackTrace();
}
}
}
} catch (MidiUnavailableException e1){
e1.printStackTrace();
}
}
}
return midiIn;
}
So the thing that's getting me here is this: alsa lists only one entry in amidi -l and when I specify that as a port to dump, it works fine. Java gets that same text entry and can't sort out the MIDI IN, assigning it the com.sun.media.sound.MidiOutDeviceProvider class so it leaves me wondering just how does, or where does Java figure out what a device has to offer and why isn't it seeing the input port that alsa is seeing.
I'm coding with eclipse Version: 3.8.1 IDE with JDK1.6, on a linux mint OS, .
I'll be happy to provide anything asked for. Thanks for reading!
The solution to java seeing the transmitter was in the version of JDK being used, though unfortunately at this time, I do not have an answer as to why for the failure, just that one version worked and suits my needs for the time being. If I find that answer, I will edit this answer.
Of the three versions I was switching between for testing, jdk1.8.0_60, jdk1.7.0_80, jdk1.6.0_45, 1.7 did not experience the error and successfully obtained a transmitter from my device. I found this out, and that privileges were not the cause of my specific issue, by compiling and running some code I found suitable for command line execution that attempts to obtain the transmitter, prints out midi data sent to it, and modified it a little ...
import javax.sound.midi.MidiDevice;
import javax.sound.midi.MidiMessage;
import javax.sound.midi.MidiSystem;
import javax.sound.midi.MidiUnavailableException;
import javax.sound.midi.Receiver;
public class MidiInputTest {
public MidiDevice input;
public MidiDevice output;
public static void main(String[] args) {
new MidiInputTest().start();
}
public void start() {
init(); // initialize your midi input device
// system dependent
try {
output.open(); // From midi device
MyReceiver myrcvr = new MyReceiver();
MidiSystem.getTransmitter().setReceiver(myrcvr);
} catch (Exception e) {
e.printStackTrace();
System.exit(0);
}
}
private class MyReceiver implements Receiver {
Receiver rcvr;
public MyReceiver() {
try {
this.rcvr = MidiSystem.getReceiver();
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
#Override
public void send(MidiMessage message, long timeStamp) {
byte[] b = message.getMessage();
if (b[0] != (byte)254) {
System.out.println((b[0] & 0xff) + " " + (b[1] & 0xff));
}
//rcvr.send(message, timeStamp); // will send out what ever you receive
}
#Override
public void close() {
rcvr.close();
}
}
public void init() {
MidiDevice.Info[] devices;
devices = MidiSystem.getMidiDeviceInfo();
try{
for (MidiDevice.Info info: devices) {
MidiDevice device;
device = MidiSystem.getMidiDevice(info);
System.out.println("MidiDevice.Info="+info + "\n" + "maxTransmitters="+device.getMaxTransmitters());
// I put the specific device I want to connect to behind an if gate here to avoid connecting to something I do not
if (info.toString().equals("Interface [hw:2,0,0]") && device.getMaxTransmitters() != 0) {
System.out.println(" Name: " + info.toString() +
", Decription: " +
info.getDescription() +
", Vendor: " +
info.getVendor());
output = MidiSystem.getMidiDevice(info);
if (! output.isOpen()) {
output.open();
}
}
}
} catch (MidiUnavailableException mue) {
mue.printStackTrace();
}
}
}
To run this from the command line choose a version of JDK you have installed, compile and run it with those specific versions substituting jdk1.7.0_80 for the distro you wish to test.
/opt/java-jdk/jdk1.7.0_80/bin/javac MidiInputTest.java
/opt/java-jdk/jdk1.7.0_80/bin/java -cp . MidiInputTest
Though I haven't been able to verify it, Java Sound is apparently responsible for figuring out what is available for java's use from your MIDI architecture.
Thank you Mike Harris for sending me down the right path of testing on the command line, and jim829 over at java-forums.org for the example code for the command line.
I had this problem which was caused by multiple instances of device info with the same name reterned by MidiSystem.getMidiDeviceInfo(). Basically when you call MidiSystem.getMidiDevice(Info) if you're unlucky it'll return the one without the transmitter. I'm not sure why it does this but only one instance has transmitters, (I think one might be for in and one out but, not sure). By first getting just the devices that have transmitters and then selecting from these, with the desired info, it worked for me. Hope that helps
public ArrayList<MidiDevice> getTransmitterDevices() {
MidiDevice.Info[] deviceInfo = MidiSystem.getMidiDeviceInfo();
ArrayList<MidiDevice> transmitterDevices = new ArrayList<>();
for(int i=0;i<deviceInfo.length;i++) {
try {
MidiDevice device = MidiSystem.getMidiDevice(deviceInfo[i]);
if(device.getMaxTransmitters()!=0) {
transmitterDevices.add(device);
}
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
return transmitterDevices;
}
//Somewhere else
//choose appropriate info somehow
MidiDevices<ArrayList> transmitterDevices = getTransmitterDevices();
for(MidiDevice tmp : transmitterDevices) {
if(tmp.getDeviceInfo().equals(info)) {
try {
midiController = tmp;
Transmitter transmitter = midiController.getTransmitter();
// something that implements receiver
midiReceiver = new MidiReceiver();
transmitter.setReceiver(midiReceiver);
midiController.open();
System.out.println("controller set ok");
} catch (MidiUnavailableException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
I want to print my file directly from webpage. For that I am using following reference and trying to implement same with ZUL and Composer.
http://tonny-bruckers.blogspot.in/2012/11/printing-files-directly-from-web-page.html
ZUL File :-
<zk>
<applet code = "PrintApplet.class" codebase = "applet/" id="printApplet" width="400px" style="border: 1px" />
<button id="btnClickMe" label="Click Me" sclass="light-btn"/>
</zk>
PrintApplet.class is present inside "WebContent/applet".
public class AppletComposer extends GenericForwardComposer<Window> {
private Applet printApplet;
public void doOverrideAfterComposer(Window comp) throws Exception {
}
public void onClick$btnClickMe(Event event) throws Exception {
String Originalstr = "ByteArrayInputStream Example!";
byte[] Originalbytes = Originalstr.getBytes();
ByteArrayInputStream bis=new ByteArrayInputStream(Originalbytes);
printApplet.invoke("print", bis);
}
}
PrintApplet Class :-
public class PrintApplet extends Applet {
public void init()
{
}
public void print(ByteArrayInputStream bis) throws PrintException
{
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
if (service != null) {
DocFlavor psFormat = DocFlavor.INPUT_STREAM.PDF;
PrintRequestAttributeSet attributes = new HashPrintRequestAttributeSet();
DocPrintJob job = service.createPrintJob();
Doc pdfDoc = new SimpleDoc(bis,psFormat, null);
job.print(pdfDoc, attributes);
}
}
}
I am able to invoke PrintApplet with this approach but getting Null as service. PrintApplet is working fine with AppletViewer and with normal Java Application but unable to get default printer service while using the above approach.
First I want to mention that APPLET IS ALWAYS RUN ON CLIENT SIDE and APPLET only communicates to the server which from it is downloaded.
That’s why we have to specify codebase directory, so that we can download the applet on client browser by then JAVA Platform Environment plugin from browser takes on control, which in turn run on client JRE environment.
So we have to be very carefully that JDK environment is installed properly.
To trace applet log we can use of java applet console tool ‘jconsole’.
Steps for APPLET to run properly on client browser :
At browser (firefox,chrome,opera) check whether JAVA Platform plugin is there or not, because to run applet from the browser we require that plugin installed and enabled.
If you are working on linux machine: than it is bit complex,
You can find how to enable plugin for LINUX-BROWSER from here:
http://www.oracle.com/technetwork/java/javase/manual-plugin-install-linux-136395.html
Enable console log for applet, when it executes on client JRE, we can look into it for tracing.
Path : JDK_DIR/bin/jcontrol
[JControl Window][1]
For only development purpose: you can lower the security
We have to clear the cache of applet, every time we build new applet, to reflect the latest change we need to clear the cache first, otherwise it'll load cached applet class.
To clear we can use 'javaws -viewer'
Path : JAVA_HOME/bin/javaws -viewer
[Clear Applet Cache][2]
As per your code, your server side code (zul and composer) are perfect but the problem is at applet code.
You are looking for a default printer in print() method, which are one time configuration codes. It has to be in init().
PrintApplet.java
public class PrintApplet extends Applet {
private static final long serialVersionUID = 1L;
private PrintService service;
public void init()
{
JOptionPane.showMessageDialog(null, "Inside INIT()");
if(null==service){
service = PrintServiceLookup.lookupDefaultPrintService();
System.out.println(service.getName());
} else {
System.out.println(service.getName());
}
}
public void print(String str) throws PrintException
{
JOptionPane.showMessageDialog(null, "Inside print()");
JOptionPane.showMessageDialog(null, "String is:::"+str);
cPrint cP = new cPrint(str, service);
System.out.println((Integer) AccessController.doPrivileged(cP));
}
}
And you need another implementation of AccessController to give access to the default printer locate and print.
cPrint.java
class cPrint implements PrivilegedAction<Object> {
String str;
PrintService service;
public cPrint(String str, PrintService argPrintService) {
this.str = str;
this.service = argPrintService;
};
public Object run() {
// privileged code goes here
InputStream is = null;
try
{
JOptionPane.showMessageDialog(null, "String is:::"+str);
byte[] Originalbytes = str.getBytes();
JOptionPane.showMessageDialog(null, "Original bytes:::"+Originalbytes);
is=new ByteArrayInputStream(Originalbytes);
FileWriter fstream = new FileWriter("/home/test/out.pdf");
BufferedWriter out = new BufferedWriter(fstream);
for (Byte b: Originalbytes) {
out.write(b);
}
out.close();
DocPrintJob printJob = service.createPrintJob();
Doc doc;
DocAttributeSet docAttrSet = new HashDocAttributeSet();
PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
doc = new SimpleDoc(is, DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
PrintJobWatcher pjDone = new PrintJobWatcher(printJob);
printJob.print(doc, printReqAttr);
pjDone.waitForDone();
// It is now safe to close the input stream
is.close();
}
catch (Exception e) {
e.printStackTrace();
System.out.println(e);
return 1;
}
return 0;
}
static class PrintJobWatcher {
// true iff it is safe to close the print job's input stream
boolean done = false;
PrintJobWatcher(DocPrintJob job) {
// Add a listener to the print job
job.addPrintJobListener(new PrintJobAdapter() {
public void printJobCanceled(PrintJobEvent pje) {
allDone();
}
public void printJobCompleted(PrintJobEvent pje) {
allDone();
}
public void printJobFailed(PrintJobEvent pje) {
allDone();
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
allDone();
}
void allDone() {
synchronized (PrintJobWatcher.this) {
done = true;
PrintJobWatcher.this.notify();
}
}
});
}
public synchronized void waitForDone() {
try {
while (!done) {
wait();
}
} catch (InterruptedException e) {
}
}
}
}
cPrint(str,PrintService)
Where str can be file name if you want file to be print, or byte array string.
Here in my example, I expected byte array, so I create pdf file from byte array given by the applet from the composer and then it'll sent to the default printer to the given PrintService.
So Actual flow for applet in zk to get access for default printer and to print is by this [graph][3].
I need to know the Printer Status. I need to control the Printer Status using Java Program.
Example
Check the Printer status, weather will it accept the Job or not,
Out of Paper
Printer queue
Toner
and etc..
I know there is a way to check the basic information, such as name, color supported or not. But I can't find any example to check paper, toner, job queue. I like to know if it is possible to using Java API. I found big API for printer function, but they didn't give a simple example how to use it.
Have a look at this PrinterStateReason. And also javax.print.
Getting the complete status of a printer is not possible. Printers have a native driver which is able to request services but because there are so many possible printer functionalities, Java only supports a subset of it.
You can actually offer the user to modify the status by calling
PrinterJob pj = PrinterJob.getPrinterJob();
pj.printDialog()
which shows the native printer dialog.
Despite the information in the javax.print API that it is possible to check the printer state, I was not able to do so for my printer !. (Canon).
Code to check:
import javax.print.*;
import javax.print.attribute.DocAttributeSet;
import javax.print.attribute.PrintServiceAttributeSet;
import javax.print.attribute.standard.PrinterStateReason;
import javax.print.attribute.standard.PrinterStateReasons;
import javax.print.attribute.standard.Severity;
import javax.print.event.*;
import java.awt.*;
import java.awt.print.PageFormat;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.*;
import java.util.Set;
/**
* PrintTest
*/
public class PrintTest implements PrintServiceAttributeListener,PrintJobListener,Doc, Printable, PrintJobAttributeListener {
private static final transient String TEXT = "12345";
public static void main(String[] args) {
PrintTest test = new PrintTest();
test.checkPrinters();
}
public void checkPrinters() {
Thread newThread = new Thread(new Runnable() {
public void run() {
PrintService ps = PrinterJob.getPrinterJob().getPrintService();
DocFlavor[] myFlavors = ps.getSupportedDocFlavors();
ps.addPrintServiceAttributeListener(PrintTest.this);
DocPrintJob docJob = ps.createPrintJob();
docJob.addPrintJobAttributeListener(PrintTest.this, null);
docJob.addPrintJobListener(PrintTest.this);
try {
docJob.print(PrintTest.this,null);
}
catch (PrintException e) {
e.printStackTrace(); //To change body of catch statement use File | Settings | File Templates.
}
} });
newThread.start();
/**
PrintServiceAttributeSet attSet = ps.getAttributes();
PrinterStateReasons psr = ps.getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
} */
}
public void attributeUpdate(PrintServiceAttributeEvent psae) {
System.out.println(psae.getAttributes());
}
public void printDataTransferCompleted(PrintJobEvent pje) {
System.out.println("Transfer completed");
}
public void printJobCompleted(PrintJobEvent pje) {
System.out.println("Completed");
}
public void printJobFailed(PrintJobEvent pje) {
System.out.println("Failed");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public void printJobCanceled(PrintJobEvent pje) {
System.out.println("Canceled");
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
System.out.println("No more events");
}
public void printJobRequiresAttention(PrintJobEvent pje) {
System.out.println("Job requires attention");
PrinterStateReasons psr = pje.getPrintJob().getPrintService().getAttribute(PrinterStateReasons.class);
if (psr != null) {
Set<PrinterStateReason> errors = psr.printerStateReasonSet(Severity.REPORT);
for (PrinterStateReason reason : errors)
System.out.printf(" Reason : %s",reason.getName());
System.out.println();
}
}
public DocFlavor getDocFlavor() {
return DocFlavor.SERVICE_FORMATTED.PRINTABLE; //To change body of implemented methods use File | Settings | File Templates.
}
public Object getPrintData() throws IOException {
return this;
}
public DocAttributeSet getAttributes() {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public Reader getReaderForText() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public InputStream getStreamForBytes() throws IOException {
return null; //To change body of implemented methods use File | Settings | File Templates.
}
public int print(Graphics graphics, PageFormat pageFormat, int pageIndex) throws PrinterException {
return pageIndex == 0 ? PAGE_EXISTS : NO_SUCH_PAGE; //To change body of implemented methods use File | Settings | File Templates.
}
public void attributeUpdate(PrintJobAttributeEvent pjae) {
System.out.println("Look out");
}
}
I have tried to get a PrinterReasonsState by willfully opening the case or removing the paper, but I was unsuccessfull. Perhaps someone else can show how it is possible, but so far it seems that the API offers much more functionality which is in reality not available.
Or in short:
It does not work, at least not for my printer.
I was told one could check the printer status this way:
PrintService printService = PrintServiceLookup.lookupDefaultPrintService();
AttributeSet attributes = printService.getAttributes();
String printerState = attributes.get(PrinterState.class).toString();
String printerStateReason = attributes.get(PrinterStateReason.class).toString();
System.out.println("printerState = " + printerState); // May be IDLE, PROCESSING, STOPPED or UNKNOWN
System.out.println("printerStateReason = " + printerStateReason); // If your printer state returns STOPPED, for example, you can identify the reason
if (printerState.equals(PrinterState.STOPPED.toString()) {
if (printerStateReason.equals(PrinterStateReason.TONER_LOW.toString()) {
System.out.println("Toner level is low.");
}
}
Sadly it seems that my printer doesn't have support for printerState so I can't test it.
UPDATE:
Instead of querying WMI "win32_printer" object I would recommend using Powershell directly like this, its much cleaner API :
Get-Printer | where PrinterStatus -like 'Normal' | fl
To see all the printers and statuses:
Get-Printer | fl Name, PrinterStatus
To see all the attributes:
Get-Printer | fl
You can still use ProcessBuilder in Java as described below.
Before update:
Solution for Windows only.
In Windows you can query WMI "win32_printer" class, so you check that the state on OS layer: Win32_Printer class
In Java you can use ProcessBuilder like this to start PowerShell and execute the PS script like this:
String printerName = "POS_PRINTER";
ProcessBuilder builder = new ProcessBuilder("powershell.exe", "get-wmiobject -class win32_printer | Select-Object Name, PrinterState, PrinterStatus | where {$_.Name -eq '"+printerName+"'}");
String fullStatus = null;
Process reg;
builder.redirectErrorStream(true);
try {
reg = builder.start();
fullStatus = getStringFromInputStream(reg.getInputStream());
reg.destroy();
} catch (IOException e1) {
// TODO Auto-generated catch block
e1.printStackTrace();
}
System.out.print(fullStatus);
After converting the InputStream to String you should get something like that:
Name PrinterState PrinterStatus
---- ------------ -------------
POS_PRINTER 0 3
State and Status should change for various situations (printer turned off, out of paper, cover opened,...).
This should work, but depends on the printer and drivers. I used this with EPSON TM printers with ESDPRT port and I could get information like: no paper, cover open, printer offline/turned off, printer paused.
More comprehensive answer here:
- my StackOverflow answer on a similar question.
i require to send a pdf document to print on the server side of a web app, the printer fully supports pdf printing etc, it is networked as well to the server. The pdf is also stored on the server.
what i am trying to is on a button click, print out the pdf file, currently i have the code below :
//Server side printing
public class PrintDocument {
public void printText(String text) throws PrintException, IOException {
//Looks for all printers
//PrintService[] printServices = PrinterJob.lookupPrintServices();
PrintService service = PrintServiceLookup.lookupDefaultPrintService();
InputStream is = new ByteArrayInputStream(text.getBytes("UTF8"));
PrintRequestAttributeSet pras = new HashPrintRequestAttributeSet();
pras.add(new Copies(1));
DocFlavor flavor = DocFlavor.INPUT_STREAM.AUTOSENSE;
Doc doc = new SimpleDoc(is, flavor, null);
DocPrintJob job = service.createPrintJob();
PrintJobWatcher pjw = new PrintJobWatcher(job);
job.print(doc, pras);
pjw.waitForDone();
is.close();
}
}
class PrintJobWatcher {
boolean done = false;
PrintJobWatcher(DocPrintJob job) {
job.addPrintJobListener(new PrintJobAdapter() {
public void printJobCanceled(PrintJobEvent pje) {
allDone();
}
public void printJobCompleted(PrintJobEvent pje) {
allDone();
}
public void printJobFailed(PrintJobEvent pje) {
allDone();
}
public void printJobNoMoreEvents(PrintJobEvent pje) {
allDone();
}
void allDone() {
synchronized (PrintJobWatcher.this) {
done = true;
System.out.println("Printing has successfully completed, please collect your prints)");
PrintJobWatcher.this.notify();
}
}
});
}
public synchronized void waitForDone() {
try {
while (!done) {
wait();
}
} catch (InterruptedException e) {
}
}
}
But i have a few questions / issues, how do i put the pdf into the input stream for this to be printed out, can i select options such as duplex printing, and how can i call this from inside a JSF web app
Thanks
According to this article it should be possible to start a print job with a PJL block (Wikipedia link includes pointers to the PJL reference documentation), followed by the PDF data.
Thank to PJL you should be able to control all features the printer has to offer including duplex, etc - the blog article even mentions stapling of a combined printout of 2 pdfs.
Be sure to read the comments on the article as well, there is a comment from the guy who's listed as inventor on the patent as well with extra information on the PJL commands.
Take a look at this blog. We had to print documents with duplex print option.
Its not possible to duplex print directly in java. However the work around is to use ghostscript and convert PDF to PS (Post script file). To that you can add either PJL Commands or Post script commands.
More info at
http://reddymails.blogspot.com/2014/07/how-to-print-documents-using-java-how.html
Also read similar question
Printing with Attributes(Tray Control, Duplex, etc...) using javax.print library
After reading through this Q&A I spent awhile working with the javax.print library only to discover that it is not very consistent with printer option support. I.e. even if a printer has an option like stapling, the javax.printer library showed it as "stapling not supported".
So I then tried out PJL commands using a plain java socket and it worked great, in my tests it also printed faster than the javax.print library, it has a much smaller code footprint and best part is no libraries are needed at all:
private static void print(File document, String printerIpAddress)
{
try (Socket socket = new Socket(printerIpAddress, 9100))
{
DataOutputStream out = new DataOutputStream(socket.getOutputStream());
String title = document.getName();
byte[] bytes = Files.readAllBytes(document.toPath());
out.write(27);
out.write("%-12345X#PJL\n".getBytes());
out.write(("#PJL SET JOBNAME=" + title + "\n").getBytes());
out.write("#PJL SET DUPLEX=ON\n".getBytes());
out.write("#PJL SET STAPLEOPTION=ONE\n".getBytes());
out.write("#PJL ENTER LANGUAGE=PDF\n".getBytes());
out.write(bytes);
out.write(27);
out.write("%-12345X".getBytes());
out.flush();
out.close();
}
catch (Exception e)
{
System.out.println(e);
}
}
See this for more info on attempts with javax.print.
I'm working on an Java applet that prints a file.
The applet is "self-signed".
The print function is:
//argFilePath : path to file (http://localhost/Teste/pdf1.pdf)
//argPrintService : something like PrintServiceLookup.lookupDefaultPrintService()
private int print(String argFilePath, PrintService argPrintService){
try
{
DocPrintJob printJob = argPrintService.createPrintJob();
Doc doc;
DocAttributeSet docAttrSet = new HashDocAttributeSet();
PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
URL url = new URL(argFilePath);
doc = new SimpleDoc(url.openStream(), DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
printJob.print(doc, printReqAttr);
} catch (Exception e) {
System.out.println(e);
return 1;
}
return 0;
}
I get this exception when trying to open the file:
java.security.AccessControlException: access denied (java.net.SocketPermission 127.0.0.1:80 connect,resolve)
HTML/JavaScrip
<input onclick="alert(document.getElementById('xpto').print('http://localhost/Teste/pdf1.pdf'));" type="button"/>
<applet width="180" height="120" code="printers.class" id="xpto" archive="printerAPI.jar"></applet>
is correct to use:
DocFlavor.INPUT_STREAM.AUTOSENSE
The idea seems to be to print as many file type as possible - pdf, docx, jpg, etc.
How can you fix the exception?
Found the answer (on stackoverflow lol :D)!
It looks like the problem was:
"javascript does not have file access permissions"
so the applet is blocked. we have to use
AccessController.doPrivileged()
doPrivileged
Here is my implementation:
private int print(String argFilePath, PrintService argPrintService){
cPrint cP = new cPrint(argFilePath, argPrintService);
return (Integer) AccessController.doPrivileged(cP);
}
class cPrint implements PrivilegedAction<Object> {
String FilePath;
PrintService PrintService;
public cPrint(String argFilePath, PrintService argPrintService) {
this.FilePath = argFilePath;
this.PrintService = argPrintService;
};
public Object run() {
// privileged code goes here
try
{
DocPrintJob printJob = PrintService.createPrintJob();
Doc doc;
DocAttributeSet docAttrSet = new HashDocAttributeSet();
PrintRequestAttributeSet printReqAttr = new HashPrintRequestAttributeSet();
URL url = new URL(FilePath);
doc = new SimpleDoc(url.openStream(), DocFlavor.INPUT_STREAM.AUTOSENSE, docAttrSet);
printJob.print(doc, printReqAttr);
} catch (Exception e) {
System.out.println(e);
return 1;
}
return 0;
}
}
You probably got this:
java.security.AccessControlException: access denied (java.net.SocketPermission
127.0.0.1:80 connect,resolve)
because applets can't make connections to websites, other than the one they came from. Now, this is terribly silly because one would think localhost is not another website, but the Java SecurityManager must only look at IP address. Therefore, if the browser is connected to 74.125.224.224 then the Java applet must connect to that address—which is different from localhost, whose address is 127.0.0.1.
This will just take care of the Socket Permission error. But, you'll probably run into something else if you're trying to access the user's hardware. In which case, you'll need to make a certificate and the user will choose whether or not to run your applet.
If you just want to run this on your home computer then, you need a plain-text java.policy file in your home directory. (~/.java.policy for Unix people.) In that file you'll type:
grant{
permission java.security.AllPermission;
};
After you save this file in your home directory, all java applets will be given full permission to run—anything. It'll be like the SecurityManager doesn't exist, so try to be a bit careful. After you're done with testing, I'd recommend to delete this file.