/**
* ===========================================
* Java Pdf Extraction Decoding Access Library
* ===========================================
*
* Project Info: http://www.jpedal.org
* (C) Copyright 1997-2008, IDRsolutions and Contributors.
*
* This file is part of JPedal
*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* ---------------
* Printer.java
* ---------------
*/
package org.jpedal.examples.simpleviewer.utils;
import java.awt.*;
import java.awt.color.ColorSpace;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import javax.print.*;
import javax.print.attribute.*;
import javax.print.attribute.standard.Chromaticity;
import javax.print.attribute.standard.Copies;
import javax.print.attribute.standard.JobName;
import javax.print.attribute.standard.PageRanges;
import javax.print.attribute.standard.PrinterResolution;
import javax.print.event.PrintJobEvent;
import javax.print.event.PrintJobListener;
import javax.swing.JOptionPane;
import javax.swing.ProgressMonitor;
import javax.swing.Timer;
import org.jpedal.PdfDecoder;
import org.jpedal.color.PdfPaint;
import org.jpedal.examples.simpleviewer.gui.popups.PrintPanel;
import org.jpedal.exception.PdfException;
import org.jpedal.external.ColorHandler;
import org.jpedal.external.Options;
import org.jpedal.gui.GUIFactory;
import org.jpedal.objects.PrinterOptions;
import org.jpedal.utils.LogWriter;
import org.jpedal.utils.Messages;
public class Printer {
//<start-gpl>
/**flag to stop mutliple prints*/
private static int printingThreads = 0;
/**page range to print*/
int rangeStart = 1, rangeEnd = 1;
/**type of printing - all, odd, even*/
int subset = PrinterOptions.ALL_PAGES;
/**Check to see if Printing cancelled*/
boolean wasCancelled = false;
/**Allow Printing Cancelled to appear once*/
boolean messageShown = false;
boolean pagesReversed = false;
/**provide user with visual clue to print progress*/
Timer updatePrinterProgress = null;
private ProgressMonitor status = null;
/** needs to be global for the printer selection to work */
private DocPrintJob printJob = null;
// for use with fest testing
public static boolean showOptionPane = true;
// public static int count;
public void printPDF(final PdfDecoder decode_pdf, final GUIFactory currentGUI, final String blacklist, final String defaultPrinter, final boolean debugPrinting) {
//provides atomic flag on printing so we don't exit until all done
printingThreads++;
/**
* printing in thread to improve background printing -
* comment out if not required
*/
Thread worker = new Thread() {
public void run() {
boolean printFile = false;
try {
PageFormat pf = PrinterJob.getPrinterJob().defaultPage();
/**
* default page size
*/
Paper paper = new Paper();
paper.setSize(595, 842);
paper.setImageableArea(43, 43, 509, 756);
pf.setPaper(paper);
/**
* workaround to improve performance on PCL printing
* by printing using drawString or Java's glyph if font
* available in Java
*/
//decode_pdf.setTextPrint(PdfDecoder.NOTEXTPRINT); //normal mode - only needed to reset
//decode_pdf.setTextPrint(PdfDecoder.TEXTGLYPHPRINT); //intermediate mode - let Java create Glyphs if font matches
//decode_pdf.setTextPrint(PdfDecoder.TEXTSTRINGPRINT); //try and get Java to do all the work
//wrap in Doc as we can then add a listeners
Doc doc = new SimpleDoc(decode_pdf, DocFlavor.SERVICE_FORMATTED.PAGEABLE, null);
//setup default values to padd into JPS
PrintRequestAttributeSet aset = new HashPrintRequestAttributeSet();
aset.add(new PageRanges(1, decode_pdf.getPageCount()));
// useful debugging code to show supported values and values returned by printer
//Attribute[] settings = aset.toArray();
//Class[] attribs=printJob.getPrintService().getSupportedAttributeCategories();
//for(int i=0;i<attribs.length;i++)
//System.out.println(i+" "+attribs[i]);
//for(int i=0;i<settings.length;i++) //show values set by printer
// System.out.println(i+" "+settings[i].toString()+" "+settings[i].getName());
/**
* custom dialog so we can copy Acrobat PDF settings
* (removed from OS versions)
*/
/*
/**/
PrintPanel printPanel = (PrintPanel) currentGUI.printDialog(getAvailablePrinters(blacklist), defaultPrinter);
printFile = printPanel.okClicked();
//ensure PDF display reappears
decode_pdf.repaint();
// set values in JPS
// choose the printer, testing if printer in list
setPrinter(printPanel.getPrinter());
//range of pages
int printMode = 0;
subset = PrinterOptions.ALL_PAGES;
if (printPanel.isOddPagesOnly()) {
printMode = PrinterOptions.ODD_PAGES_ONLY;
subset = PrinterOptions.ODD_PAGES_ONLY;
} else if (printPanel.isEvenPagesOnly()) {
printMode = PrinterOptions.EVEN_PAGES_ONLY;
subset = PrinterOptions.EVEN_PAGES_ONLY;
}
//flag to show reversed
pagesReversed = printPanel.isPagesReversed();
if (pagesReversed) {
printMode = printMode + PrinterOptions.PRINT_PAGES_REVERSED;
}
decode_pdf.setPrintPageMode(printMode);
//can also take values such as new PageRanges("3,5,7-9,15");
SetOfIntegerSyntax range = printPanel.getPrintRange();
//store color handler in case it needs to be replaced for grayscale printing
Object storedColorHandler = decode_pdf.getExternalHandler(Options.ColorHandler);
if (range == null) {
currentGUI.showMessageDialog("No pages to print");
} else {
decode_pdf.setPagePrintRange(range);
// workout values for progress monitor
rangeStart = range.next(0); // find first
// find last
int i = rangeStart;
rangeEnd = rangeStart;
if (range.contains(2147483647)) //allow for all returning largest int
{
rangeEnd = decode_pdf.getPageCount();
} else {
while (range.next(i) != -1) {
i++;
}
rangeEnd = i;
}
//pass through number of copies
aset.add(new Copies(printPanel.getCopies()));
//Auto-rotate and scale flag
decode_pdf.setPrintAutoRotateAndCenter(printPanel.isAutoRotateAndCenter());
// Are we printing the current area only
decode_pdf.setPrintCurrentView(printPanel.isPrintingCurrentView());
//set mode - see org.jpedal.objects.contstants.PrinterOptions for all values
decode_pdf.setPrintPageScalingMode(printPanel.getPageScaling());
//Set whether to print in monochrome or full color
if (printPanel.isMonochrome()) {
aset.remove(Chromaticity.COLOR);
aset.add(Chromaticity.MONOCHROME);
decode_pdf.addExternalHandler(new ColorHandler() {
public void setPaint(Graphics2D g2, PdfPaint textFillCol, int pageNumber, boolean isPrinting) {
//converts to grayscale for printing
if(isPrinting && textFillCol!=null){ //only on printout
int rgb=textFillCol.getRGB();
//get the value
float[] val=new float[3];
val[0]=((rgb>>16) & 255)/255f;
val[1]=((rgb>>8) & 255)/255f;
val[2]=(rgb & 255)/255f;
//to gray
ColorSpace cs=ColorSpace.getInstance(ColorSpace.CS_GRAY);
float[] grayVal=cs.fromRGB(val);
Color colGray= new Color(cs,grayVal,1f);
g2.setPaint(colGray);
}else
g2.setPaint(textFillCol);
}
public BufferedImage processImage(BufferedImage image, int pageNumber, boolean isPrinting) {
if(isPrinting && image != null){ //only on printout
//grayscale conversion
BufferedImage newImage = new BufferedImage(image.getWidth(), image.getHeight(), BufferedImage.TYPE_BYTE_GRAY);
Graphics2D newG2=newImage.createGraphics();
newG2.setPaint(Color.WHITE);
newG2.fillRect(0,0,image.getWidth(), image.getHeight());
newG2.drawImage(image,0,0,null);
return newImage;
}
return image;
}
}, Options.ColorHandler);
} else {
aset.remove(Chromaticity.MONOCHROME);
aset.add(Chromaticity.COLOR);
}
//set paper size
if (printPanel.getSelectedPaper() != null) {
pf.setPaper(printPanel.getSelectedPaper());
}
decode_pdf.setPageFormat(pf);
// flag if we use paper size or PDF size
decode_pdf.setUsePDFPaperSize(printPanel.isPaperSourceByPDFSize());
//Set print resolution
PrinterResolution res = printPanel.getResolution();
if (res != null) {
aset.add(res);
}
}
/**/
/**
* popup to show user progress
*/
if (showOptionPane) {
status = new ProgressMonitor(currentGUI.getFrame(), "", "", 1, 100);
/** used to track user stopping movement and call refresh every 2 seconds*/
updatePrinterProgress = new Timer(1000, new ActionListener() {
public void actionPerformed(ActionEvent event) {
int currentPage = decode_pdf.getCurrentPrintPage();
if (currentPage > 0) {
updatePrinterProgess(decode_pdf, currentPage);
}
//make sure turned off
if (currentPage == -1) {
updatePrinterProgress.stop();
status.close();
}
}
});
updatePrinterProgress.setRepeats(true);
updatePrinterProgress.start();
}
//Name the print job the same as the Pdf file.
String name=decode_pdf.getFileName();
if(name==null){ //can be null if we pass in PDF as byte[] array
name="JPedal printing";
}else{
String[] jobString = decode_pdf.getFileName().split("/");
JobName jobName = new JobName(jobString[jobString.length-1], null);
if(printJob.getPrintService().isAttributeValueSupported(jobName, DocFlavor.SERVICE_FORMATTED.PAGEABLE, aset)) {
aset.add(jobName);
}
}
/**
* actual print call
*/
if (printFile) {
//used to track print activity
printJob.addPrintJobListener(new PDFPrintJobListener());
//Print PDF document
printJob.print(doc, aset);
}
//Restore color handler in case grayscale printing was used
decode_pdf.addExternalHandler(storedColorHandler, Options.ColorHandler);
} catch (PrinterException ee) {
ee.printStackTrace();
LogWriter.writeLog("Exception " + ee + " printing");
currentGUI.showMessageDialog(ee.getMessage() + ' ' + ee + ' ' + ' ' + ee.getCause());
} catch (Exception e) {
LogWriter.writeLog("Exception " + e + " printing");
e.printStackTrace();
currentGUI.showMessageDialog("Exception " + e);
} catch (Error err) {
err.printStackTrace();
LogWriter.writeLog("Error " + err + " printing");
currentGUI.showMessageDialog("Error " + err);
}
/**
* visual print update progress box
*/
if (updatePrinterProgress != null) {
updatePrinterProgress.stop();
status.close();
}
/**report any or our errors
* (we do it this way rather than via PrinterException as MAC OS X has a nasty bug in PrinterException)
*/
if (!printFile && !decode_pdf.isPageSuccessful()) {
String errorMessage = Messages.getMessage("PdfViewerError.ProblemsEncountered") + decode_pdf.getPageFailureMessage() + '\n';
if (decode_pdf.getPageFailureMessage().toLowerCase().indexOf("memory") != -1) {
errorMessage += Messages.getMessage("PdfViewerError.RerunJava")
+ Messages.getMessage("PdfViewerError.RerunJava1")
+ Messages.getMessage("PdfViewerError.RerunJava2");
}
currentGUI.showMessageDialog(errorMessage);
}
printingThreads--;
//redraw to clean up
decode_pdf.resetCurrentPrintPage();
decode_pdf.invalidate();
decode_pdf.updateUI();
decode_pdf.repaint();
if ((printFile && !wasCancelled)) {
if (showOptionPane) {
currentGUI.showMessageDialog(Messages.getMessage("PdfViewerPrintingFinished"));
}
}
}
};
//start printing in background (comment out if not required)
worker.start();
}
public static String[] getAvailablePrinters(String blacklist) {
PrintService[] service=PrinterJob.lookupPrintServices();
int noOfPrinters = service.length;
String[] serviceNames = new String[noOfPrinters];
//check blacklist
if (blacklist != null) {
String[] bl = blacklist.split(",");
int count = 0;
//loop through printservices
for (int i=0; i<service.length; i++) {
boolean pass = true;
String name = service[i].getName();
//loop through blacklist items
for (int j=0; j<bl.length; j++) {
//check for wildcard
if (bl[j].indexOf("*")!=-1) {
String term = bl[j].replace("*","").trim();
if(name.indexOf(term)!=-1)
pass = false;
} else if (name.toLowerCase().equals(bl[j].toLowerCase()))
pass = false;
}
//Add to array
if (pass) {
serviceNames[count] = name;
count++;
}
}
//Trim array
String[] temp = serviceNames;
serviceNames = new String[count];
System.arraycopy(temp,0,serviceNames,0,count);
} else {
for(int i=0;i<noOfPrinters;i++)
serviceNames[i] = service[i].getName();
}
return serviceNames;
}
/**visual print indicator*/
private String dots=".";
private void updatePrinterProgess(PdfDecoder decode_pdf,int currentPage) {
//Calculate no of pages printing
int noOfPagesPrinting=(rangeEnd-rangeStart+1);
//Calculate which page we are currently printing
int currentPrintingPage=(currentPage-rangeStart);
int actualCount=noOfPagesPrinting;
int actualPage=currentPrintingPage;
int actualPercentage= (int) (((float)actualPage/(float)actualCount)*100);
if(status.isCanceled()){
decode_pdf.stopPrinting();
updatePrinterProgress.stop();
status.close();
wasCancelled=true;
printingThreads--;
if(!messageShown){
JOptionPane.showMessageDialog(null,Messages.getMessage("PdfViewerPrint.PrintingCanceled"));
messageShown=true;
}
return;
}
//update visual clue
dots=dots+ '.';
if(dots.length()>8)
dots=".";
//allow for backwards
boolean isBackwards=((currentPrintingPage<=0));
if(rangeStart==rangeEnd)
isBackwards=false;
if((isBackwards))
noOfPagesPrinting=(rangeStart-rangeEnd+1);
int percentage = (int) (((float)currentPrintingPage / (float)noOfPagesPrinting) * 100);
if((!isBackwards)&&(percentage<1))
percentage=1;
//invert percentage so percentage works correctly
if(isBackwards){
percentage=-percentage;
currentPrintingPage=-currentPrintingPage;
}
if(pagesReversed)
percentage=100-percentage;
status.setProgress(percentage);
String message="";
if(subset==PrinterOptions.ODD_PAGES_ONLY){
actualCount=((actualCount/2)+1);
actualPage=actualPage/2;
}else if(subset==PrinterOptions.EVEN_PAGES_ONLY){
actualCount=((actualCount/2)+1);
actualPage=actualPage/2;
}
/*
* allow for printing 1 page
* Set to page 1 of 1 like Adobe
*/
if (actualCount==1){
actualPercentage=50;
actualPage=1;
status.setProgress(actualPercentage);
}
message=actualPage + " "+Messages.getMessage("PdfViewerPrint.Of")+ ' ' +
actualCount + ": " + actualPercentage + '%' + ' ' +dots;
if(pagesReversed){
message=(actualCount-actualPage) + " "+Messages.getMessage("PdfViewerPrint.Of")+ ' ' +
actualCount + ": " + percentage + '%' + ' ' +dots;
status.setNote(Messages.getMessage("PdfViewerPrint.ReversedPrinting")+ ' ' + message);
}else if(isBackwards)
status.setNote(Messages.getMessage("PdfViewerPrint.ReversedPrinting")+ ' ' + message);
else
status.setNote(Messages.getMessage("PdfViewerPrint.Printing")+ ' ' + message);
}
//}
public static boolean isPrinting() {
return printingThreads>0;
}
private void setPrinter(String chosenPrinter) throws PrinterException, PdfException {
PrintService[] service=PrinterJob.lookupPrintServices(); //list of printers
int count=service.length;
boolean matchFound=false;
for(int i=0;i<count;i++){
if(service[i].getName().indexOf(chosenPrinter)!=-1){
printJob= service[i].createPrintJob();
i=count;
matchFound=true;
}
}
if(!matchFound)
throw new PdfException("Unknown printer "+chosenPrinter);
}
/**
* listener code - just an example
*/
private static class PDFPrintJobListener implements PrintJobListener {
static final private boolean showMessages=false;
public void printDataTransferCompleted(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printDataTransferCompleted="+printJobEvent.toString());
}
public void printJobCompleted(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printJobCompleted="+printJobEvent.toString());
}
public void printJobFailed(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printJobEvent="+printJobEvent.toString());
}
public void printJobCanceled(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printJobFailed="+printJobEvent.toString());
}
public void printJobNoMoreEvents(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printJobNoMoreEvents="+printJobEvent.toString());
}
public void printJobRequiresAttention(PrintJobEvent printJobEvent) {
if(showMessages)
System.out.println("printJobRequiresAttention="+printJobEvent.toString());
}
}
/**
//<end-gpl>
public static boolean isPrinting() {
return false;
}
/**/
}
|