You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@pdfbox.apache.org by ti...@apache.org on 2014/07/05 17:50:08 UTC
svn commit: r1608040 -
/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java
Author: tilman
Date: Sat Jul 5 15:50:07 2014
New Revision: 1608040
URL: http://svn.apache.org/r1608040
Log:
PDFBOX-1695: create graphic diff file, and empty files in target dir if anything goes wrong
Modified:
pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java
Modified: pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java
URL: http://svn.apache.org/viewvc/pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java?rev=1608040&r1=1608039&r2=1608040&view=diff
==============================================================================
--- pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java (original)
+++ pdfbox/trunk/pdfbox/src/test/java/org/apache/pdfbox/util/TestPDFToImage.java Sat Jul 5 15:50:07 2014
@@ -16,9 +16,12 @@
*/
package org.apache.pdfbox.util;
+import java.awt.Color;
+import java.awt.Graphics;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.FileInputStream;
+import java.io.FileOutputStream;
import java.io.FilenameFilter;
import java.io.IOException;
@@ -34,29 +37,30 @@ import org.apache.pdfbox.rendering.PDFRe
import javax.imageio.ImageIO;
/**
- * Test suite for PDFTextStripper.
+ * Test suite for rendering.
*
* FILE SET VALIDATION
*
- * This test suite is designed to test PDFToImage using a set of PDF
- * files and known good output for each. The default mode of testAll()
- * is to process each *.pdf file in "src/test/resources/input/rendering". An output file is
- * created in "target/test-output/rendering" with the same name as the PDF file, plus an
+ * This test suite is designed to test PDFToImage using a set of PDF files and
+ * known good output for each. The default mode of testAll() is to process each
+ * *.pdf file in "src/test/resources/input/rendering". An output file is created
+ * in "target/test-output/rendering" with the same name as the PDF file, plus an
* additional page number and ".png" suffix.
*
- * The output file is then tested against a known good result file from
- * the input directory (again, with the same name as the tested PDF file,
- * but with the additional page number and ".png" suffix).
+ * The output file is then tested against a known good result file from the
+ * input directory (again, with the same name as the tested PDF file, but with
+ * the additional page number and ".png" suffix).
*
- * Currently, testing against known output is simply a byte-for-byte comparison
- *
- *In the future, testing against the known output may be accomplished using PerceptualDiff
- * http://sourceforge.net/projects/pdiff
+ * If the two aren't identical, a graphical .diff.png file is created. If they
+ * are identical, the output .png file is deleted. If a "good result" file
+ * doesn't exist, the output .png file is left there for human inspection.
*
+ * Errors are flagged by creating empty files with appropriate names in the
+ * target directory.
*
* @author <a href="mailto:DanielWilson@Users.Sourceforge.net">Daniel Wilson</a>
* @author <a href="mailto:ben@benlitchfield.com">Ben Litchfield</a>
- * @version $Revision: 1.1 $
+ * @author <a href="mailto:tilman@snafu.de">Tilman Hausherr</a>
*/
public class TestPDFToImage extends TestCase
{
@@ -64,10 +68,9 @@ public class TestPDFToImage extends Test
/**
* Logger instance.
*/
- private static final Log log = LogFactory.getLog(TestPDFToImage.class);
+ private static final Log LOG = LogFactory.getLog(TestPDFToImage.class);
private boolean bFail = false;
- private PDFRenderer renderer = null;
private File mcurFile = null;
/**
@@ -77,14 +80,15 @@ public class TestPDFToImage extends Test
*
* @throws IOException If there is an error creating the test.
*/
- public TestPDFToImage( String name ) throws IOException
+ public TestPDFToImage(String name) throws IOException
{
- super( name );
+ super(name);
}
/**
* Test suite setup.
*/
+ @Override
public void setUp()
{
// If you want to test a single file using DEBUG logging, from an IDE,
@@ -94,6 +98,91 @@ public class TestPDFToImage extends Test
}
/**
+ * Create an image; the part between the smaller and the larger image is
+ * painted black, the rest in white
+ *
+ * @param minWidth width of the smaller image
+ * @param minHeight width of the smaller image
+ * @param maxWidth height of the larger image
+ * @param maxHeight height of the larger image
+ *
+ * @return
+ */
+ private BufferedImage createEmptyDiffImage(int minWidth, int minHeight, int maxWidth, int maxHeight)
+ {
+ BufferedImage bim3 = new BufferedImage(maxWidth, maxHeight, BufferedImage.TYPE_INT_RGB);
+ Graphics graphics = bim3.getGraphics();
+ if (minWidth != maxWidth || minHeight != maxHeight)
+ {
+ graphics.setColor(Color.BLACK);
+ graphics.fillRect(0, 0, maxWidth, maxHeight);
+ }
+ graphics.setColor(Color.WHITE);
+ graphics.fillRect(0, 0, minWidth, minHeight);
+ graphics.dispose();
+ return bim3;
+ }
+
+ /**
+ * Get the difference between two images, identical colors are set to white,
+ * differences are xored, the highest bit of each color is reset to avoid
+ * colors that are too light
+ *
+ * @param bim1
+ * @param bim2
+ * @return If the images are different, the function returns a diff image If
+ * the images are identical, the function returns null If the size is
+ * different, a black border on the botton and the right is created
+ *
+ * @throws IOException
+ */
+ BufferedImage diffImages(BufferedImage bim1, BufferedImage bim2) throws IOException
+ {
+ int minWidth = Math.min(bim1.getWidth(), bim2.getWidth());
+ int minHeight = Math.min(bim1.getHeight(), bim2.getHeight());
+ int maxWidth = Math.max(bim1.getWidth(), bim2.getWidth());
+ int maxHeight = Math.max(bim1.getHeight(), bim2.getHeight());
+ BufferedImage bim3 = null;
+ if (minWidth != maxWidth || minHeight != maxHeight)
+ {
+ bim3 = createEmptyDiffImage(minWidth, minHeight, maxWidth, maxHeight);
+ }
+ for (int x = 0; x < minWidth; ++x)
+ {
+ for (int y = 0; y < minHeight; ++y)
+ {
+ int rgb1 = bim1.getRGB(x, y);
+ int rgb2 = bim2.getRGB(x, y);
+ if (rgb1 != rgb2
+ // don't bother about differences of 1 color step
+ && (Math.abs((rgb1 & 0xFF) - (rgb2 & 0xFF)) > 1)
+ && (Math.abs(((rgb1 >> 8) & 0xFF) - ((rgb2 >> 8) & 0xFF)) > 1)
+ && (Math.abs(((rgb1 >> 16) & 0xFF) - ((rgb2 >> 16) & 0xFF)) > 1))
+ {
+ if (bim3 == null)
+ {
+ bim3 = createEmptyDiffImage(minWidth, minHeight, maxWidth, maxHeight);
+ }
+ int rgb3 = (rgb1 ^ rgb2) & 0x7f7f7f; // 7f is to avoid colors that are too light and won't be seen
+ if (rgb3 == 0)
+ {
+ rgb3 = 0x808080;
+ }
+ bim3.setRGB(x, y, rgb3);
+ }
+ else
+ {
+ if (bim3 != null)
+ {
+ bim3.setRGB(x, y, Color.WHITE.getRGB());
+ }
+ }
+ }
+ }
+ return bim3;
+ }
+
+ /**
* Validate text extraction on a single file.
*
* @param file The file to validate
@@ -103,63 +192,132 @@ public class TestPDFToImage extends Test
* @throws Exception when there is an exception
*/
public void doTestFile(File file, boolean bLogResult, String inDir, String outDir)
- throws Exception
+ throws Exception
{
PDDocument document = null;
- log.info("Preparing to convert " + file.getName());
+ LOG.info("Opening: " + file.getName());
try
{
- document = PDDocument.load(file);
- renderer = new PDFRenderer(document);
-
+ new FileOutputStream(new File(outDir + file.getName() + ".parseerror")).close();
+ document = PDDocument.loadNonSeq(file, null);
String outputPrefix = outDir + file.getName() + "-";
int numPages = document.getNumberOfPages();
+ if (numPages < 1)
+ {
+ this.bFail = true;
+ LOG.error("file " + file.getName() + " has < 1 page");
+ }
+ else
+ {
+ new File(outDir + file.getName() + ".parseerror").delete();
+ }
+
+ try
+ {
+ // Check for version difference between load() and loadNonSeq()
+ new FileOutputStream(new File(outDir + file.getName() + ".parseseqerror")).close();
+ PDDocument doc2 = PDDocument.load(file, null);
+ if (doc2.getDocument().getVersion() != document.getDocument().getVersion())
+ {
+ new FileOutputStream(new File(outDir + file.getName() + ".versiondiff")).close();
+ }
+ doc2.close();
+ new File(outDir + file.getName() + ".parseseqerror").delete();
+ }
+ catch (IOException ex)
+ {
+ }
+ LOG.info("Rendering: " + file.getName());
PDFRenderer renderer = new PDFRenderer(document);
for (int i = 0; i < numPages; i++)
{
+ String fileName = outputPrefix + (i + 1) + ".png";
+ new FileOutputStream(new File(fileName + ".rendererror")).close();
BufferedImage image = renderer.renderImageWithDPI(i, 96); // Windows native DPI
- String fileName = outputPrefix + (i + 1);
- log.info("Writing: " + fileName + ".pbg");
- ImageIO.write(image, "PNG", new File(fileName));
+ new File(fileName + ".rendererror").delete();
+ LOG.info("Writing: " + fileName);
+ new FileOutputStream(new File(fileName + ".writeerror")).close();
+ ImageIOUtil.writeImage(image, fileName, 96);
+ new File(fileName + ".writeerror").delete();
}
+
+ // test to see whether file is destroyed in pdfbox
+ File tmpFile = File.createTempFile("pdfbox", ".pdf");
+ document.save(tmpFile);
+ PDDocument.loadNonSeq(tmpFile, null).close();
+ tmpFile.delete();
}
- catch(Exception e)
- {
- this.bFail=true;
- log.error("Error converting file " + file.getName(), e);
+ catch (Exception e)
+ {
+ this.bFail = true;
+ LOG.error("Error converting file " + file.getName(), e);
}
finally
{
- document.close();
+ if (document != null)
+ {
+ document.close();
+ }
}
+ LOG.info("Comparing: " + file.getName());
+
//Now check the resulting files ... did we get identical PNG(s)?
try
{
+ new File(outDir + file.getName() + ".cmperror").delete();
+
mcurFile = file;
File[] outFiles = new File(outDir).listFiles(new FilenameFilter()
- {
+ {
public boolean accept(File dir, String name)
{
- return (name.endsWith(".png") && name.startsWith(mcurFile.getName(),0));
+ return (name.endsWith(".png") && name.startsWith(mcurFile.getName(), 0));
}
- });
- for (File outFile : outFiles)
+ });
+ for (int n = 0; n < outFiles.length; n++)
{
- File inFile = new File(inDir + '/' + outFile.getName());
- if (!inFile.exists() || !filesAreIdentical(outFile, inFile))
+ new File(outFiles[n].getAbsolutePath() + "-diff.png").delete(); // delete diff file from a previous run
+
+ File inFile = new File(inDir + '/' + outFiles[n].getName());
+ if (!inFile.exists())
{
- this.bFail=true;
- log.warn("*** TEST FAILURE *** Input and output not identical for file: " + inFile.getName());
+ this.bFail = true;
+ LOG.warn("*** TEST FAILURE *** Input missing for file: " + inFile.getName());
+ }
+ else if (!filesAreIdentical(outFiles[n], inFile))
+ {
+ // different files might still have identical content
+ // save the difference (if any) into a diff image
+ BufferedImage bim3 = diffImages(ImageIO.read(inFile), ImageIO.read(outFiles[n]));
+ if (bim3 != null)
+ {
+ this.bFail = true;
+ LOG.warn("*** TEST FAILURE *** Input and output not identical for file: " + inFile.getName());
+ ImageIO.write(bim3, "png", new File(outFiles[n].getAbsolutePath() + "-diff.png"));
+ }
+ else
+ {
+ LOG.info("*** TEST OK *** for file: " + inFile.getName());
+ LOG.info("Deleting: " + outFiles[n].getName());
+ outFiles[n].delete();
+ }
+ }
+ else
+ {
+ LOG.info("*** TEST OK *** for file: " + inFile.getName());
+ LOG.info("Deleting: " + outFiles[n].getName());
+ outFiles[n].delete();
}
}
}
- catch(Exception e)
+ catch (Exception e)
{
- this.bFail=true;
- log.error("Error comparing file output for " + file.getName(), e);
+ new FileOutputStream(new File(outDir + file.getName() + ".cmperror")).close();
+ this.bFail = true;
+ LOG.error("Error comparing file output for " + file.getName(), e);
}
}
@@ -170,7 +328,7 @@ public class TestPDFToImage extends Test
* @throws Exception when there is an exception
*/
public void testRenderImage()
- throws Exception
+ throws Exception
{
String filename = System.getProperty("org.apache.pdfbox.util.TextStripper.file");
String inDir = "src/test/resources/input/rendering";
@@ -178,42 +336,47 @@ public class TestPDFToImage extends Test
String inDirExt = "target/test-input-ext/rendering";
String outDirExt = "target/test-output-ext/rendering";
- if ((filename == null) || (filename.length() == 0))
+ new File(outDir).mkdirs();
+
+ if ((filename == null) || (filename.length() == 0))
+ {
+ File[] testFiles = new File(inDir).listFiles(new FilenameFilter()
{
- File[] testFiles = new File(inDir).listFiles(new FilenameFilter()
+ @Override
+ public boolean accept(File dir, String name)
{
- public boolean accept(File dir, String name)
- {
- return (name.endsWith(".pdf") || name.endsWith(".ai"));
- }
- });
+ return (name.endsWith(".pdf") || name.endsWith(".ai"));
+ }
+ });
for (File testFile : testFiles)
{
doTestFile(testFile, false, inDir, outDir);
}
- testFiles = new File(inDirExt).listFiles(new FilenameFilter()
+ testFiles = new File(inDirExt).listFiles(new FilenameFilter()
+ {
+ @Override
+ public boolean accept(File dir, String name)
{
- public boolean accept(File dir, String name)
- {
- return (name.endsWith(".pdf") || name.endsWith(".ai"));
- }
- });
- if (testFiles != null)
+ return (name.endsWith(".pdf") || name.endsWith(".ai"));
+ }
+ });
+ if (testFiles != null)
+ {
+ for (File testFile : testFiles)
{
- for (File testFile : testFiles) {
doTestFile(testFile, false, inDirExt, outDirExt);
}
- }
- }
- else
- {
- doTestFile(new File(inDir, filename), true, inDir, outDir);
}
+ }
+ else
+ {
+ doTestFile(new File(inDir, filename), true, inDir, outDir);
+ }
- if (this.bFail)
- {
- fail("One or more failures, see test log for details");
- }
+ if (this.bFail)
+ {
+ fail("One or more failures, see test log for details");
+ }
}
/**
@@ -223,7 +386,7 @@ public class TestPDFToImage extends Test
*/
public static Test suite()
{
- return new TestSuite( TestPDFToImage.class );
+ return new TestSuite(TestPDFToImage.class);
}
/**
@@ -231,23 +394,27 @@ public class TestPDFToImage extends Test
*
* @param args Command line arguments.
*/
- public static void main( String[] args )
+ public static void main(String[] args)
{
- String[] arg = {TestPDFToImage.class.getName() };
- junit.textui.TestRunner.main( arg );
+ String[] arg =
+ {
+ TestPDFToImage.class.getName()
+ };
+ junit.textui.TestRunner.main(arg);
}
private boolean filesAreIdentical(File left, File right) throws IOException
{
//http://forum.java.sun.com/thread.jspa?threadID=688105&messageID=4003259
+ //http://web.archive.org/web/20060515173719/http://forum.java.sun.com/thread.jspa?threadID=688105&messageID=4003259
/* -- I reworked ASSERT's into IF statement -- dwilson
- assert left != null;
- assert right != null;
- assert left.exists();
- assert right.exists();
- */
- if(left != null && right != null && left.exists() && right.exists())
+ assert left != null;
+ assert right != null;
+ assert left.exists();
+ assert right.exists();
+ */
+ if (left != null && right != null && left.exists() && right.exists())
{
if (left.length() != right.length())
{