/*
GNU GENERAL LICENSE
Copyright (C) 2006 The Lobo Project. Copyright (C) 2014 - 2017 Lobo Evolution
This program is free software; you can redistribute it and/or
modify it under the terms of the GNU General Public
License as published by the Free Software Foundation; either
verion 3 of the License, or (at your option) any later version.
This program 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
General License for more details.
You should have received a copy of the GNU General Public
along with this program. If not, see <http://www.gnu.org/licenses/>.
Contact info: lobochief@users.sourceforge.net; ivan.difrancesco@yahoo.it
*/
package org.lobobrowser.primary.gui.pdf;
import java.awt.BorderLayout;
import java.awt.Container;
import java.awt.Frame;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Rectangle;
import java.awt.event.ActionEvent;
import java.awt.print.Book;
import java.awt.print.PageFormat;
import java.awt.print.Paper;
import java.awt.print.Printable;
import java.awt.print.PrinterException;
import java.awt.print.PrinterJob;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.nio.ByteBuffer;
import java.nio.channels.FileChannel;
import javax.swing.AbstractAction;
import javax.swing.Box;
import javax.swing.JButton;
import javax.swing.JDialog;
import javax.swing.JLabel;
import org.apache.logging.log4j.Level;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import com.sun.pdfview.PDFFile;
import com.sun.pdfview.PDFPage;
import com.sun.pdfview.PDFRenderer;
/**
* A class representing a print job for a particular PDFFile. The class
* maintains a status dialog as it prints, allowing the user to cancel the print
* job.
*/
public class PDFPrintPage implements Printable {
/** The Constant logger. */
private static final Logger logger = LogManager.getLogger(PDFPrintPage.class);
/** The PDFFile to be printed. */
private PDFFile file;
/** The PrinterJob for this print job. */
private PrinterJob pjob;
/** A dialog box indicating printing status, with cancel button. */
private JDialog pd;
/** The text in the progress dialog indicating the current page. */
private JLabel pagenumlabel;
/** The cancel button in the progress dialog. */
private JButton cancel;
/**
* Create a new PDFPrintPage object for a particular PDFFile.
*
* @param file
* the PDFFile to be printed.
*/
public PDFPrintPage(PDFFile file) {
this.file = file;
}
/**
* An example method to print a file.
*
* @param filename
* The path of the PDF file to print.
* @param setupPaper
* true to post a page setup dialog
* @throws java.io.IOException
*/
public void printFile(String filename, boolean setupPaper) throws IOException {
FileInputStream fis = null;
try {
File file = new File(filename);
fis = new FileInputStream(file);
FileChannel fc = fis.getChannel();
ByteBuffer bb = fc.map(FileChannel.MapMode.READ_ONLY, 0, fc.size());
PDFFile pdfFile = new PDFFile(bb); // Create PDF Print Page
PDFPrintPage pages = new PDFPrintPage(pdfFile);
// Create Print Job.
// We set the margins to 0, on the default 8.5 x 11 paper
PrinterJob pjob = PrinterJob.getPrinterJob();
PageFormat pfDefault = PrinterJob.getPrinterJob().defaultPage();
Paper defaultPaper = new Paper();
defaultPaper.setImageableArea(0, 0, defaultPaper.getWidth(), defaultPaper.getHeight());
pfDefault.setPaper(defaultPaper);
if (setupPaper) {
pfDefault = PrinterJob.getPrinterJob().pageDialog(pfDefault);
}
pjob.setJobName(file.getName());
if (pjob.printDialog()) {
// validate the page against the chosen printer to correct
// paper settings and margins
pfDefault = pjob.validatePage(pfDefault);
Book book = new Book();
book.append(pages, pfDefault, pdfFile.getNumPages());
pjob.setPageable(book);
try {
pjob.print();
} catch (PrinterException exc) {
logger.log(Level.ERROR,exc);
}
}
} finally {
if (fis != null) {
fis.close();
}
}
}
/**
* Generates the status dialog with cancel button.
*/
private void createPrintDialog() {
pd = new JDialog((Frame) null, "Printing...", false);
Container top = pd.getContentPane();
Box lines = Box.createVerticalBox();
Box line = Box.createHorizontalBox();
line.add(new JLabel("Now printing: "));
JLabel title = new JLabel("file.pdf");
line.add(title);
lines.add(line);
line = Box.createHorizontalBox();
line.add(Box.createHorizontalStrut(10));
line.add(new JLabel("page "));
pagenumlabel = new JLabel("1");
line.add(pagenumlabel);
line.add(new JLabel(" of "));
JLabel totalpages = new JLabel(String.valueOf(file.getNumPages()));
line.add(totalpages);
lines.add(line);
top.add(lines, BorderLayout.CENTER);
Box cancelbox = Box.createHorizontalBox();
cancelbox.add(Box.createHorizontalGlue());
cancel = new JButton(new AbstractAction("Cancel") {
private static final long serialVersionUID = 1L;
@Override
public void actionPerformed(ActionEvent evt) {
doCancel();
}
});
cancelbox.add(cancel);
top.add(cancelbox, BorderLayout.SOUTH);
}
/**
* Show the progress dialog for this print job
*
* @param pjob
* the PrinterJob representing the print job
*/
public void show(PrinterJob pjob) {
this.pjob = pjob;
if (pd == null) {
createPrintDialog();
}
pd.pack();
pd.setVisible(true);
}
/**
* Close the progress dialog. Don't use this method to cancel the print job;
* use {@link #doCancel doCancel} instead.
*/
public void hide() {
pd.dispose();
}
/**
* Cancel the print job. Disables the cancel button, as it might take a
* while for the cancel to take effect.
*/
public void doCancel() {
cancel.setEnabled(false);
pjob.cancel();
}
// from Printable interface: prints a single page, given a Graphics
// to draw into, the page format, and the page number.
@Override
public int print(Graphics g, PageFormat format, int index) throws PrinterException {
int pagenum = index + 1;
// don't bother if the page number is out of range.
if ((pagenum >= 1) && (pagenum <= file.getNumPages())) {
// update the page number in the progress dialog
if (pagenumlabel != null) {
pagenumlabel.setText(String.valueOf(pagenum));
}
// fit the PDFPage into the printing area
Graphics2D g2 = (Graphics2D) g;
PDFPage page = file.getPage(pagenum);
double pwidth = format.getImageableWidth();
double pheight = format.getImageableHeight();
double aspect = page.getAspectRatio();
// handle page orientation matching
double paperaspect = pwidth / pheight;
if (paperaspect < 1.0) {
switch (format.getOrientation()) {
case PageFormat.REVERSE_LANDSCAPE:
case PageFormat.LANDSCAPE:
format.setOrientation(PageFormat.PORTRAIT);
break;
case PageFormat.PORTRAIT:
format.setOrientation(PageFormat.LANDSCAPE);
break;
}
pwidth = format.getImageableWidth();
pheight = format.getImageableHeight();
paperaspect = pwidth / pheight;
}
Rectangle imgbounds;
int width;
int height;
if (aspect > paperaspect) {
// paper is too tall / pdfpage is too wide
height = (int) (pwidth / aspect);
width = (int) pwidth;
} else {
// paper is too wide / pdfpage is too tall
width = (int) (pheight * aspect);
height = (int) pheight;
}
imgbounds = new Rectangle((int) format.getImageableX(), (int) format.getImageableY(), width, height);
// render the page
PDFRenderer pgs = new PDFRenderer(page, g2, imgbounds, null, null);
try {
page.waitForFinish();
pgs.run();
} catch (InterruptedException ie) {
}
return PAGE_EXISTS;
} else {
return NO_SUCH_PAGE;
}
}
}