From 87f892d9d8b3e6459e19538156a70632a1bb4e6f Mon Sep 17 00:00:00 2001 From: Jeremias Maerki Date: Sat, 15 Oct 2011 10:32:15 +0000 Subject: [PATCH] Restored PDFDocumentGraphics2D functionality. Bugfix: NPE after PDFDocumentGraphics2D.create() due to missing font setup and other missing initializations. Bugfix: Properly handle state in PDFGraphics2D.drawString(). Added an example class demonstrating the use of PDFDocumentGraphics2D. git-svn-id: https://svn.apache.org/repos/asf/xmlgraphics/fop/trunk@1183620 13f79535-47bb-0310-9956-ffa450edef68 --- .../java/embedding/ExampleJava2D2PDF.java | 180 ++++++++++++++++++ .../apache/fop/svg/PDFDocumentGraphics2D.java | 4 + .../org/apache/fop/svg/PDFGraphics2D.java | 16 +- status.xml | 3 + .../org/apache/fop/UtilityCodeTestSuite.java | 4 +- .../pdf/PDFDocumentGraphics2DTestCase.java | 93 +++++++++ 6 files changed, 293 insertions(+), 7 deletions(-) create mode 100644 examples/embedding/java/embedding/ExampleJava2D2PDF.java create mode 100644 test/java/org/apache/fop/pdf/PDFDocumentGraphics2DTestCase.java diff --git a/examples/embedding/java/embedding/ExampleJava2D2PDF.java b/examples/embedding/java/embedding/ExampleJava2D2PDF.java new file mode 100644 index 000000000..ff9807165 --- /dev/null +++ b/examples/embedding/java/embedding/ExampleJava2D2PDF.java @@ -0,0 +1,180 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package embedding; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; +import java.io.File; +import java.io.IOException; +import java.io.OutputStream; +import java.io.StringReader; + +import javax.swing.JEditorPane; + +import org.apache.avalon.framework.configuration.Configuration; +import org.apache.avalon.framework.configuration.ConfigurationException; +import org.apache.avalon.framework.configuration.DefaultConfiguration; +import org.apache.commons.io.IOUtils; + +import org.apache.xmlgraphics.util.UnitConv; + +import org.apache.fop.svg.PDFDocumentGraphics2D; +import org.apache.fop.svg.PDFDocumentGraphics2DConfigurator; + +/** + * This example class demonstrates the use of {@link PDFDocumentGraphics2D} that can be + * used to create a PDF file from Java2D graphics (using the {@link Graphics2D} API). + */ +public class ExampleJava2D2PDF { + + private Configuration createAutoFontsConfiguration() { + //Create a default configuration using auto-detection of fonts. + //This can be a bit slow but covers most use cases. + DefaultConfiguration c = new DefaultConfiguration("cfg"); + DefaultConfiguration fonts = new DefaultConfiguration("fonts"); + c.addChild(fonts); + DefaultConfiguration autodetect = new DefaultConfiguration("auto-detect"); + fonts.addChild(autodetect); + return c; + + /* You can also load the configuration from a file: + DefaultConfigurationBuilder cfgBuilder = new DefaultConfigurationBuilder(); + return cfgBuilder.buildFromFile(configFile); + */ + } + + private void configure(PDFDocumentGraphics2D g2d, Configuration cfg) + throws ConfigurationException { + + PDFDocumentGraphics2DConfigurator configurator = new PDFDocumentGraphics2DConfigurator(); + configurator.configure(g2d, cfg); + } + + /** + * Creates a PDF file. The contents are painted using a Graphics2D implementation that + * generates an PDF file. + * @param outputFile the target file + * @throws IOException In case of an I/O error + * @throws ConfigurationException if an error occurs configuring the PDF output + */ + public void generatePDF(File outputFile) throws IOException, ConfigurationException { + OutputStream out = new java.io.FileOutputStream(outputFile); + out = new java.io.BufferedOutputStream(out); + try { + + //Instantiate the PDFDocumentGraphics2D instance + PDFDocumentGraphics2D g2d = new PDFDocumentGraphics2D(false); + g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + + //Configure the G2D with the necessary fonts + configure(g2d, createAutoFontsConfiguration()); + + //Set up the document size + Dimension pageSize = new Dimension( + (int)Math.ceil(UnitConv.mm2pt(210)), + (int)Math.ceil(UnitConv.mm2pt(297))); //page size A4 (in pt) + g2d.setupDocument(out, pageSize.width, pageSize.height); + g2d.translate(144, 72); //Establish some page borders + + //A few rectangles rotated and with different color + Graphics2D copy = (Graphics2D)g2d.create(); + int c = 12; + for (int i = 0; i < c; i++) { + float f = ((i + 1) / (float)c); + Color col = new Color(0.0f, 1 - f, 0.0f); + copy.setColor(col); + copy.fillRect(70, 90, 50, 50); + copy.rotate(-2 * Math.PI / c, 70, 90); + } + copy.dispose(); + + //Some text + g2d.rotate(-0.25); + g2d.setColor(Color.RED); + g2d.setFont(new Font("sans-serif", Font.PLAIN, 36)); + g2d.drawString("Hello world!", 140, 140); + g2d.setColor(Color.RED.darker()); + g2d.setFont(new Font("serif", Font.PLAIN, 36)); + g2d.drawString("Hello world!", 140, 180); + + g2d.nextPage(); + + //Demonstrate painting rich text + String someHTML = "" + + "

Welcome to page 2!

" + + "

PDFDocumentGraphics2D Demonstration

" + + "

We can easily paint some HTML here!

" + + "

" + + "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Proin accumsan" + + " condimentum ullamcorper. Sed varius quam id arcu fermentum luctus. Praesent" + + " nisi ligula, cursus sed vestibulum vel, sodales sed lectus.

" + + ""; + JEditorPane htmlComp = new JEditorPane(); + htmlComp.setContentType("text/html"); + htmlComp.read(new StringReader(someHTML), null); + htmlComp.setSize(new Dimension(pageSize.width - 72, pageSize.height - 72)); + //htmlComp.setBackground(Color.ORANGE); + htmlComp.validate(); + htmlComp.printAll(g2d); + + //Cleanup + g2d.finish(); + } finally { + IOUtils.closeQuietly(out); + } + } + + /** + * Main method. + * @param args command-line arguments + */ + public static void main(String[] args) { + try { + System.out.println("FOP " + ExampleJava2D2PDF.class.getSimpleName() + "\n"); + System.out.println("Preparing..."); + + //Setup directories + File baseDir = new File("."); + File outDir = new File(baseDir, "out"); + if (!outDir.isDirectory()) { + if (!outDir.mkdirs()) { + throw new IOException("Could not create output directory: " + outDir); + } + } + + //Setup output file + File pdffile = new File(outDir, "ResultJava2D2PDF.pdf"); + + System.out.println("Output: PDF (" + pdffile + ")"); + System.out.println(); + System.out.println("Generating..."); + + ExampleJava2D2PDF app = new ExampleJava2D2PDF(); + app.generatePDF(pdffile); + + System.out.println("Success!"); + } catch (Throwable t) { + t.printStackTrace(System.err); + System.exit(-1); + } + } +} diff --git a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java index 829d8972d..f8f14cca2 100644 --- a/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFDocumentGraphics2D.java @@ -276,6 +276,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { } /** {@inheritDoc} */ + @Override protected void preparePainting() { if (pdfContext.isPagePending()) { return; @@ -391,7 +392,9 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { * @return a new graphics context that is a copy of * this graphics context. */ + @Override public Graphics create() { + preparePainting(); return new PDFDocumentGraphics2D(this); } @@ -403,6 +406,7 @@ public class PDFDocumentGraphics2D extends PDFGraphics2D { * @param x the x position * @param y the y position */ + @Override public void drawString(String s, float x, float y) { if (super.textAsShapes) { Font font = super.getFont(); diff --git a/src/java/org/apache/fop/svg/PDFGraphics2D.java b/src/java/org/apache/fop/svg/PDFGraphics2D.java index 4ae8e72d7..0d25e166c 100644 --- a/src/java/org/apache/fop/svg/PDFGraphics2D.java +++ b/src/java/org/apache/fop/svg/PDFGraphics2D.java @@ -751,10 +751,14 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand } boolean doWrite = false; - if (fill && paintingState.setBackColor(col)) { - doWrite = true; - } else if (paintingState.setColor(col)) { - doWrite = true; + if (fill) { + if (paintingState.setBackColor(col)) { + doWrite = true; + } + } else { + if (paintingState.setColor(col)) { + doWrite = true; + } } if (doWrite) { StringBuffer sb = new StringBuffer(); @@ -1327,7 +1331,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand } updateCurrentFont(fontState); - currentStream.write("q\n"); + saveGraphicsState(); Color c = getColor(); applyColor(c, true); @@ -1402,7 +1406,7 @@ public class PDFGraphics2D extends AbstractGraphics2D implements NativeImageHand currentStream.write("] TJ\n"); currentStream.write("ET\n"); - currentStream.write("Q\n"); + restoreGraphicsState(); } /** diff --git a/status.xml b/status.xml index 117594b79..891b62496 100644 --- a/status.xml +++ b/status.xml @@ -60,6 +60,9 @@ documents. Example: the fix of marks layering will be such a case when it's done. --> + + Various bugfixes to make PDFDocumentGraphics2D operational again. + Bugfix for when the last simple-page-master referenced in a page-sequence-master is not chosen when force-page-count=odd. diff --git a/test/java/org/apache/fop/UtilityCodeTestSuite.java b/test/java/org/apache/fop/UtilityCodeTestSuite.java index 37826954e..442d63f5b 100644 --- a/test/java/org/apache/fop/UtilityCodeTestSuite.java +++ b/test/java/org/apache/fop/UtilityCodeTestSuite.java @@ -25,6 +25,7 @@ import org.junit.runners.Suite.SuiteClasses; import org.apache.fop.events.BasicEventTestCase; import org.apache.fop.pdf.FileIDGeneratorTestCase; +import org.apache.fop.pdf.PDFDocumentGraphics2DTestCase; import org.apache.fop.pdf.PDFEncryptionJCETestCase; import org.apache.fop.pdf.PDFFactoryTestCase; import org.apache.fop.pdf.PDFObjectTestCase; @@ -51,7 +52,8 @@ import org.apache.fop.util.XMLResourceBundleTestCase; FileIDGeneratorTestCase.class, PDFFactoryTestCase.class, PDFEncryptionJCETestCase.class, - BitmapImageUtilTestCase.class + BitmapImageUtilTestCase.class, + PDFDocumentGraphics2DTestCase.class }) public class UtilityCodeTestSuite { } diff --git a/test/java/org/apache/fop/pdf/PDFDocumentGraphics2DTestCase.java b/test/java/org/apache/fop/pdf/PDFDocumentGraphics2DTestCase.java new file mode 100644 index 000000000..c7eff506e --- /dev/null +++ b/test/java/org/apache/fop/pdf/PDFDocumentGraphics2DTestCase.java @@ -0,0 +1,93 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with + * the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +/* $Id$ */ + +package org.apache.fop.pdf; + +import java.awt.Color; +import java.awt.Dimension; +import java.awt.Font; +import java.awt.Graphics2D; + +import junit.framework.Assert; + +import org.junit.Test; + +import org.apache.commons.io.output.ByteArrayOutputStream; + +import org.apache.xmlgraphics.util.UnitConv; + +import org.apache.fop.svg.PDFDocumentGraphics2D; + +/** + * Tests for {@link PDFDocumentGraphics2D}. + */ +public class PDFDocumentGraphics2DTestCase { + + /** + * Does a smoke test on PDFDocumentGraphics2D making sure that nobody accidentally broke + * anything serious. It does not check the correctness of the produced PDF. + * @throws Exception if an error occurs + */ + @Test + public void smokeTest() throws Exception { + ByteArrayOutputStream baout = new ByteArrayOutputStream(); + PDFDocumentGraphics2D g2d = new PDFDocumentGraphics2D(false); + g2d.setGraphicContext(new org.apache.xmlgraphics.java2d.GraphicContext()); + + //Set up the document size + Dimension pageSize = new Dimension( + (int)Math.ceil(UnitConv.mm2pt(210)), + (int)Math.ceil(UnitConv.mm2pt(297))); //page size A4 (in pt) + g2d.setupDocument(baout, pageSize.width, pageSize.height); + + //A few rectangles rotated and with different color + Graphics2D copy = (Graphics2D)g2d.create(); + int c = 12; + for (int i = 0; i < c; i++) { + float f = ((i + 1) / (float)c); + Color col = new Color(0.0f, 1 - f, 0.0f); + copy.setColor(col); + copy.fillRect(70, 90, 50, 50); + copy.rotate(-2 * Math.PI / c, 70, 90); + } + copy.dispose(); + + //Some text + g2d.rotate(-0.25); + g2d.setColor(Color.RED); + g2d.setFont(new Font("sans-serif", Font.PLAIN, 36)); + g2d.drawString("Hello world!", 140, 140); + g2d.setColor(Color.RED.darker()); + g2d.setFont(new Font("serif", Font.PLAIN, 36)); + g2d.drawString("Hello world!", 140, 180); + + g2d.nextPage(); //Move to next page + + g2d.setFont(new Font("sans-serif", Font.PLAIN, 36)); + g2d.drawString("Welcome to page 2!", 140, 140); + + //Cleanup + g2d.finish(); + + String pdfString = baout.toString("ISO-8859-1"); + Assert.assertEquals("%%EOF not found", + pdfString.substring(pdfString.length() - 6), "%%EOF\n"); + } + +} -- 2.39.5