Hello,
we'm using PDFBox in our current project to print a pdf file directly to an
attached network printer. Printing PDF documents having only portrait pages
within worked like a charm. Thank you very much for this!
However we experienced problems with PDFs having LANDSCAPE pages defined,
as the orientation is currently always defined by the printer service and
not by the PDDocument. This may be desireable in some situations but
undesirable in others (like others). Printing PDFs with PORTRAIT and
LANDSCAPE pages in one document may lead to strange print results as the
landscape pages are truncated to a PORTRAIT width.
To allow the user of the PDFBox API to choose which orientation
determination algorithm he wants to use, I've changed the current 1.7.1
version so that an "OrientationResolver" can be handled to the print
methods. This OrientationResolver will be used by the PDPageable to
determine the format of the page to be printed.
Please have a look at the attached patch. It was inspired by the comment in
Bug https://issues.apache.org/jira/browse/PDFBOX-985.
I currently don't know what negative implications my patch has as I haven't
fully grasped other usages of the print method, but it definitly helped me
printing LANDSCAPE pages correctly. Also, I would like to know what I'll
have to do to contribute this patch to the trunk. Whom do I have to contact?
Thank you very much in advance.
Greetings,
Thorsten Hake
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
index fbbd295..63ccb91 100644
--- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDDocument.java
@@ -69,6 +69,8 @@
import org.apache.pdfbox.pdmodel.interactive.digitalsignature.SignatureOptions;
import org.apache.pdfbox.pdmodel.interactive.form.PDAcroForm;
import org.apache.pdfbox.pdmodel.interactive.form.PDSignatureField;
+import org.apache.pdfbox.pdmodel.orientation.OrientationResolver;
+import org.apache.pdfbox.pdmodel.orientation.PrintServiceOrientationResolver;
/**
* This is the in-memory representation of the PDF document. You need to call
@@ -1260,6 +1262,19 @@
{
print(printJob, false);
}
+ /**
+ * @see PDDocument#print()
+ *
+ * @param printJob The printer job.
+ * @param resolver the orientation resolver
+ *
+ * @throws PrinterException If there is an error while sending the PDF to
+ * the printer, or you do not have permissions to print this document.
+ */
+ public void print(PrinterJob printJob, OrientationResolver resolver)
throws PrinterException
+ {
+ print(printJob, false, resolver);
+ }
/**
* This will send the PDF document to a printer. The printing
functionality
@@ -1304,17 +1319,32 @@
{
print(printJob, true);
}
-
- private void print(PrinterJob job, boolean silent) throws PrinterException
{
+ /**
+ * This will send the PDF to the default printer without prompting the user
+ * for any printer settings.
+ *
+ * @param printJob A printer job definition.
+ * @param resolver specify a resolver for the orientation of the print
see {@link OrientationResolver}
+ * @see PDDocument#print()
+ *
+ * @throws PrinterException If there is an error while printing.
+ */
+ public void silentPrint( PrinterJob printJob, OrientationResolver
resolver) throws PrinterException{
+ print(printJob, true, resolver);
+ }
+ private void print(PrinterJob job, boolean silent, OrientationResolver
resolver) throws PrinterException {
if (job == null) {
throw new PrinterException("The given printer job is null.");
} else {
- job.setPageable(new PDPageable(this, job));
+ job.setPageable(new PDPageable(this, job, resolver));
if (silent || job.printDialog()) {
job.print();
}
}
}
+ private void print(PrinterJob job, boolean silent) throws PrinterException
{
+ print(job, silent, new PrintServiceOrientationResolver());
+ }
/**
* This will close the underlying COSDocument object.
diff --git a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageable.java
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageable.java
index 5e82c99..2d133a7 100644
--- a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageable.java
+++ b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/PDPageable.java
@@ -16,7 +16,6 @@
*/
package org.apache.pdfbox.pdmodel;
-import static javax.print.attribute.standard.OrientationRequested.LANDSCAPE;
import java.awt.Dimension;
import java.awt.Graphics;
@@ -29,162 +28,224 @@
import java.util.ArrayList;
import java.util.List;
-import javax.print.PrintService;
-import javax.print.attribute.standard.OrientationRequested;
+import org.apache.pdfbox.pdmodel.orientation.OrientationResolver;
+import org.apache.pdfbox.pdmodel.orientation.PrintServiceOrientationResolver;
+
/**
* Adapter class that implements the {@link Pageable} and {@link Printable}
* interfaces for printing a given PDF document. Note that the given PDF
* document should not be modified (pages added, removed, etc.) while an
* instance of this class is being used.
- *
+ *
* @since Apache PDFBox 1.3.0
- * @see <a
href="https://issues.apache.org/jira/browse/PDFBOX-788">PDFBOX-788</a>
+ * @see <a
+ * href="https://issues.apache.org/jira/browse/PDFBOX-788">PDFBOX-788</a>
*/
public class PDPageable implements Pageable, Printable {
- /**
- * List of all pages in the given PDF document.
- */
- private final List<PDPage> pages = new ArrayList<PDPage>();
+ /**
+ * List of all pages in the given PDF document.
+ */
+ private final List<PDPage> pages = new ArrayList<PDPage>();
- /**
- * The printer job for printing the given PDF document.
- */
- private final PrinterJob job;
+ /**
+ * The printer job for printing the given PDF document.
+ */
+ private final PrinterJob job;
+
+ /**
+ * Responsible to resolve the correnct orientation.
+ */
+ private OrientationResolver orientationResolver;
+ /**
+ * Creates a {@link Pageable} adapter for the given PDF document and
printer
+ * job.
+ *
+ * @param document
+ * PDF document
+ * @param job
+ * printer job
+ * @throws IllegalArgumentException
+ * if an argument is <code>null</code>
+ * @throws PrinterException
+ * if the document permissions prevent printing
+ */
+ public PDPageable(PDDocument document, PrinterJob job,
OrientationResolver orientationResolver)
+ throws IllegalArgumentException, PrinterException {
+ if (document == null || job == null) {
+ throw new IllegalArgumentException("PDPageable(" +
document + ", "
+ + job + ")");
+ } else if (!document.getCurrentAccessPermission().canPrint()) {
+ throw new PrinterException(
+ "You do not have permission to print
this document");
+ } else {
+
document.getDocumentCatalog().getPages().getAllKids(pages);
+ this.job = job;
+ this.orientationResolver = orientationResolver;
+ }
+ }
+ /**
+ * Creates a {@link Pageable} adapter for the given PDF document and
printer
+ * job.
+ *
+ * @param document
+ * PDF document
+ * @param job
+ * printer job
+ * @throws IllegalArgumentException
+ * if an argument is <code>null</code>
+ * @throws PrinterException
+ * if the document permissions prevent printing
+ */
+ public PDPageable(PDDocument document, PrinterJob job)
+ throws IllegalArgumentException, PrinterException {
+ this(document, job, new PrintServiceOrientationResolver());
+ }
- /**
- * Creates a {@link Pageable} adapter for the given PDF document and
- * printer job.
- *
- * @param document PDF document
- * @param job printer job
- * @throws IllegalArgumentException if an argument is <code>null</code>
- * @throws PrinterException if the document permissions prevent printing
- */
- public PDPageable(PDDocument document, PrinterJob job)
- throws IllegalArgumentException, PrinterException {
- if (document == null || job == null) {
- throw new IllegalArgumentException(
- "PDPageable(" + document + ", " + job + ")");
- } else if (!document.getCurrentAccessPermission().canPrint()) {
- throw new PrinterException(
- "You do not have permission to print this document");
- } else {
- document.getDocumentCatalog().getPages().getAllKids(pages);
- this.job = job;
- }
- }
+ /**
+ * Creates a {@link Pageable} adapter for the given PDF document using a
+ * default printer job returned by {@link PrinterJob#getPrinterJob()}.
+ *
+ * @param document
+ * PDF document
+ * @throws IllegalArgumentException
+ * if the argument is <code>null</code>
+ * @throws PrinterException
+ * if the document permissions prevent printing
+ */
+ public PDPageable(PDDocument document) throws IllegalArgumentException,
+ PrinterException {
+ this(document, PrinterJob.getPrinterJob());
+ }
- /**
- * Creates a {@link Pageable} adapter for the given PDF document using
- * a default printer job returned by {@link PrinterJob#getPrinterJob()}.
- *
- * @param document PDF document
- * @throws IllegalArgumentException if the argument is <code>null</code>
- * @throws PrinterException if the document permissions prevent printing
- */
- public PDPageable(PDDocument document)
- throws IllegalArgumentException, PrinterException {
- this(document, PrinterJob.getPrinterJob());
- }
+ /**
+ * Returns the printer job for printing the given PDF document.
+ *
+ * @return printer job
+ */
+ public PrinterJob getPrinterJob() {
+ return job;
+ }
- /**
- * Returns the printer job for printing the given PDF document.
- *
- * @return printer job
- */
- public PrinterJob getPrinterJob() {
- return job;
- }
+ // ------------------------------------------------------------<
Pageable >
- //------------------------------------------------------------< Pageable >
+ /**
+ * Returns the number of pages in the given PDF document.
+ *
+ * @return number of pages
+ */
+ public int getNumberOfPages() {
+ return pages.size();
+ }
- /**
- * Returns the number of pages in the given PDF document.
- *
- * @return number of pages
- */
- public int getNumberOfPages() {
- return pages.size();
- }
+ /**
+ * Returns the format of the page at the given index.
+ *
+ * @param i
+ * page index, zero-based
+ * @return page format
+ * @throws IndexOutOfBoundsException
+ * if the page index is invalid
+ */
+ public PageFormat getPageFormat(int i) throws IndexOutOfBoundsException
{
+ PageFormat format = job.defaultPage();
- /**
- * Returns the format of the page at the given index.
- *
- * @param i page index, zero-based
- * @return page format
- * @throws IndexOutOfBoundsException if the page index is invalid
- */
- public PageFormat getPageFormat(int i) throws IndexOutOfBoundsException {
- PageFormat format = job.defaultPage();
+ PDPage page = pages.get(i); // can throw IOOBE
- PDPage page = pages.get(i); // can throw IOOBE
- Dimension media = page.findMediaBox().createDimension();
- Dimension crop = page.findCropBox().createDimension();
+ Dimension media = page.findMediaBox().createDimension();
+ Dimension crop = page.findCropBox().createDimension();
- // Center the ImageableArea if the crop is smaller than the media
- double diffWidth = 0.0;
- double diffHeight = 0.0;
- if (!media.equals(crop)) {
- diffWidth = (media.getWidth() - crop.getWidth()) / 2.0;
- diffHeight = (media.getHeight() - crop.getHeight()) / 2.0;
- }
+ // Center the ImageableArea if the crop is smaller than the
media
+ double diffWidth = 0.0;
+ double diffHeight = 0.0;
+ if (!media.equals(crop)) {
+ diffWidth = (media.getWidth() - crop.getWidth()) / 2.0;
+ diffHeight = (media.getHeight() - crop.getHeight()) /
2.0;
+ }
+ //resolve the orientation
+ int orientation = orientationResolver.resolveOrientation(page,
job);
+ format.setOrientation(orientation);
+ Paper paper = format.getPaper();
+ if (orientation == PageFormat.LANDSCAPE) {
+ paper.setImageableArea(diffHeight, diffWidth,
crop.getHeight(),
+ crop.getWidth());
+ paper.setSize(media.getHeight(), media.getWidth());
+ } else {
+ paper.setImageableArea(diffWidth, diffHeight,
crop.getWidth(),
+ crop.getHeight());
+ paper.setSize(media.getWidth(), media.getHeight());
+ }
+ format.setPaper(paper);
+ /*
+ *
+ * PageFormat format = job.defaultPage();
+ *
+ * PDPage page = pages.get(i); // can throw IOOBE Dimension
media =
+ * page.findMediaBox().createDimension(); Dimension crop =
+ * page.findCropBox().createDimension();
+ *
+ * // Center the ImageableArea if the crop is smaller than the
media
+ * double diffWidth = 0.0; double diffHeight = 0.0; if
+ * (!media.equals(crop)) { diffWidth = (media.getWidth() -
+ * crop.getWidth()) / 2.0; diffHeight = (media.getHeight() -
+ * crop.getHeight()) / 2.0; }
+ *
+ * Paper paper = format.getPaper(); PrintService service =
+ * job.getPrintService(); // can be null
Class<OrientationRequested>
+ * orientation = OrientationRequested.class; if (service !=
null &&
+ * service.getDefaultAttributeValue(orientation) == LANDSCAPE) {
+ * format.setOrientation(PageFormat.LANDSCAPE);
paper.setImageableArea(
+ * diffHeight, diffWidth, crop.getHeight(), crop.getWidth());
+ * paper.setSize(media.getHeight(), media.getWidth()); } else {
+ * format.setOrientation(PageFormat.PORTRAIT);
paper.setImageableArea(
+ * diffWidth, diffHeight, crop.getWidth(), crop.getHeight());
+ * paper.setSize(media.getWidth(), media.getHeight()); }
+ * format.setPaper(paper);
+ */
+ return format;
+ }
- Paper paper = format.getPaper();
- PrintService service = job.getPrintService(); // can be null
- Class<OrientationRequested> orientation = OrientationRequested.class;
- if (service != null
- && service.getDefaultAttributeValue(orientation) == LANDSCAPE)
{
- format.setOrientation(PageFormat.LANDSCAPE);
- paper.setImageableArea(
- diffHeight, diffWidth, crop.getHeight(), crop.getWidth());
- paper.setSize(media.getHeight(), media.getWidth());
- } else {
- format.setOrientation(PageFormat.PORTRAIT);
- paper.setImageableArea(
- diffWidth, diffHeight, crop.getWidth(), crop.getHeight());
- paper.setSize(media.getWidth(), media.getHeight());
- }
- format.setPaper(paper);
+ /**
+ * Returns a {@link Printable} for the page at the given index.
Currently
+ * this method simply returns the underlying {@link PDPage} object that
+ * directly implements the {@link Printable} interface, but future
versions
+ * may choose to return a different adapter instance.
+ *
+ * @param i
+ * page index, zero-based
+ * @return printable
+ * @throws IndexOutOfBoundsException
+ * if the page index is invalid
+ */
+ public Printable getPrintable(int i) throws IndexOutOfBoundsException {
+ return pages.get(i);
+ }
- return format;
- }
+ // -----------------------------------------------------------<
Printable >
- /**
- * Returns a {@link Printable} for the page at the given index.
- * Currently this method simply returns the underlying {@link PDPage}
- * object that directly implements the {@link Printable} interface, but
- * future versions may choose to return a different adapter instance.
- *
- * @param i page index, zero-based
- * @return printable
- * @throws IndexOutOfBoundsException if the page index is invalid
- */
- public Printable getPrintable(int i) throws IndexOutOfBoundsException {
- return pages.get(i);
- }
-
- //-----------------------------------------------------------< Printable >
-
- /**
- * Prints the page at the given index.
- *
- * @param graphics printing target
- * @param format page format
- * @param i page index, zero-based
- * @return {@link Printable#PAGE_EXISTS} if the page was printed,
- * or {@link Printable#NO_SUCH_PAGE} if page index was invalid
- * @throws PrinterException if printing failed
- */
- @SuppressWarnings("deprecation")
- public int print(Graphics graphics, PageFormat format, int i)
- throws PrinterException {
- if (0 <= i && i < pages.size()) {
- return pages.get(i).print(graphics, format, i);
- } else {
- return NO_SUCH_PAGE;
- }
- }
+ /**
+ * Prints the page at the given index.
+ *
+ * @param graphics
+ * printing target
+ * @param format
+ * page format
+ * @param i
+ * page index, zero-based
+ * @return {@link Printable#PAGE_EXISTS} if the page was printed, or
+ * {@link Printable#NO_SUCH_PAGE} if page index was invalid
+ * @throws PrinterException
+ * if printing failed
+ */
+ @SuppressWarnings("deprecation")
+ public int print(Graphics graphics, PageFormat format, int i)
+ throws PrinterException {
+ if (0 <= i && i < pages.size()) {
+ return pages.get(i).print(graphics, format, i);
+ } else {
+ return NO_SUCH_PAGE;
+ }
+ }
}
diff --git
a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/DocumentOrientationResolver.java
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/DocumentOrientationResolver.java
new file mode 100644
index 0000000..466d598
--- /dev/null
+++
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/DocumentOrientationResolver.java
@@ -0,0 +1,28 @@
+package org.apache.pdfbox.pdmodel.orientation;
+
+import java.awt.Dimension;
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+
+import org.apache.pdfbox.pdmodel.PDPage;
+/**
+ * Resolves the orientation based on the PDDocument regardless
+ * of the printer job settings.
+ */
+public class DocumentOrientationResolver implements OrientationResolver{
+
+ public int resolveOrientation(PDPage page,
+ PrinterJob job) {
+ Dimension media = page.findMediaBox().createDimension();
+ //Per default the orientation is PORTRAIT.
+ int orientation = PageFormat.PORTRAIT;
+ //Check the rotation of the page ... seems to be unreliable ...
checking just to be sure
+ int rotation = page.findRotation();
+ //Determine the orientation only based on the current page. Not
based on the printer service.
+ if (rotation == 90 || rotation == 270 || (rotation == 0 &&
media.getWidth() > media.getHeight())){
+ orientation = PageFormat.LANDSCAPE;
+ }
+ return orientation;
+ }
+
+}
\ No newline at end of file
diff --git
a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/OrientationResolver.java
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/OrientationResolver.java
new file mode 100644
index 0000000..087de49
--- /dev/null
+++
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/OrientationResolver.java
@@ -0,0 +1,9 @@
+package org.apache.pdfbox.pdmodel.orientation;
+
+import java.awt.print.PrinterJob;
+
+import org.apache.pdfbox.pdmodel.PDPage;
+
+public interface OrientationResolver{
+ public int resolveOrientation(PDPage page, PrinterJob job);
+}
\ No newline at end of file
diff --git
a/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/PrintServiceOrientationResolver.java
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/PrintServiceOrientationResolver.java
new file mode 100644
index 0000000..21c6c5d
--- /dev/null
+++
b/pdfbox/src/main/java/org/apache/pdfbox/pdmodel/orientation/PrintServiceOrientationResolver.java
@@ -0,0 +1,25 @@
+package org.apache.pdfbox.pdmodel.orientation;
+
+import static javax.print.attribute.standard.OrientationRequested.LANDSCAPE;
+
+import java.awt.print.PageFormat;
+import java.awt.print.PrinterJob;
+
+import javax.print.PrintService;
+import javax.print.attribute.standard.OrientationRequested;
+
+import org.apache.pdfbox.pdmodel.PDPage;
+/**
+ * Resolves the orientation based on the printer job, regardless of the
document settings.
+ */
+public class PrintServiceOrientationResolver implements OrientationResolver{
+
+ public int resolveOrientation(PDPage page,
+ PrinterJob job) {
+ PrintService service = job.getPrintService(); // can be null
+ int orientation = (service != null
+ &&
service.getDefaultAttributeValue(OrientationRequested.class) == LANDSCAPE) ?
PageFormat.LANDSCAPE : PageFormat.PORTRAIT;
+ return orientation;
+ }
+
+}
\ No newline at end of file