Skip to content

Commit ce8bbac

Browse files
author
Evgeniy Prudnikov
committed
Improve input processing for ImageMagick and Ghostscript
DEV-2010
1 parent 88737e7 commit ce8bbac

15 files changed

+427
-60
lines changed

itext/src/main/java/com/itextpdf/testutils/CompareTool.java

+92-58
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,25 @@
4848
import com.itextpdf.text.Meta;
4949
import com.itextpdf.text.Rectangle;
5050
import com.itextpdf.text.io.RandomAccessSourceFactory;
51-
import com.itextpdf.text.pdf.*;
51+
import com.itextpdf.text.pdf.PRIndirectReference;
52+
import com.itextpdf.text.pdf.PRStream;
53+
import com.itextpdf.text.pdf.PRTokeniser;
54+
import com.itextpdf.text.pdf.PdfAnnotation;
55+
import com.itextpdf.text.pdf.PdfArray;
56+
import com.itextpdf.text.pdf.PdfBoolean;
57+
import com.itextpdf.text.pdf.PdfContentByte;
58+
import com.itextpdf.text.pdf.PdfContentParser;
59+
import com.itextpdf.text.pdf.PdfDictionary;
60+
import com.itextpdf.text.pdf.PdfIndirectReference;
61+
import com.itextpdf.text.pdf.PdfLiteral;
62+
import com.itextpdf.text.pdf.PdfName;
63+
import com.itextpdf.text.pdf.PdfNumber;
64+
import com.itextpdf.text.pdf.PdfObject;
65+
import com.itextpdf.text.pdf.PdfReader;
66+
import com.itextpdf.text.pdf.PdfStamper;
67+
import com.itextpdf.text.pdf.PdfString;
68+
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
69+
import com.itextpdf.text.pdf.RefKey;
5270
import com.itextpdf.text.pdf.parser.ContentByteUtils;
5371
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
5472
import com.itextpdf.text.pdf.parser.InlineImageInfo;
@@ -89,9 +107,8 @@
89107
import java.util.Map;
90108
import java.util.Set;
91109
import java.util.Stack;
92-
import java.util.StringTokenizer;
93110
import java.util.TreeSet;
94-
111+
import java.util.regex.Pattern;
95112
import javax.xml.XMLConstants;
96113
import javax.xml.parsers.DocumentBuilder;
97114
import javax.xml.parsers.DocumentBuilderFactory;
@@ -102,7 +119,6 @@
102119
import javax.xml.transform.TransformerFactory;
103120
import javax.xml.transform.dom.DOMSource;
104121
import javax.xml.transform.stream.StreamResult;
105-
106122
import org.w3c.dom.Document;
107123
import org.w3c.dom.Element;
108124
import org.w3c.dom.Node;
@@ -392,9 +408,17 @@ public void writeReportToXml(OutputStream stream) throws ParserConfigurationExce
392408

393409
private String gsExec;
394410
private String compareExec;
395-
private final String gsParams = " -dNOPAUSE -dBATCH -sDEVICE=png16m -r150 -sOutputFile=<outputfile> <inputfile>";
411+
private static final String renderedImageExtension = "png";
412+
private static final String pageNumberPattern = "%03d";
413+
private static final Pattern pageListRegexp = Pattern.compile("^(\\d+,)*\\d+$");
414+
private static final String tempFilePrefix = "itext_gs_io_temp";
415+
416+
417+
private final String gsParams = " -dNOPAUSE -dBATCH -dSAFER -sDEVICE=" +
418+
renderedImageExtension + "16m -r150 -sOutputFile=<outputfile> <inputfile>";
396419
private final String compareParams = " \"<image1>\" \"<image2>\" \"<difference>\"";
397420

421+
398422
static private final String cannotOpenTargetDirectory = "Cannot open target directory for <filename>.";
399423
static private final String gsFailed = "GhostScript failed for <filename>.";
400424
static private final String unexpectedNumberOfPages = "Unexpected number of pages for <filename>.";
@@ -462,7 +486,6 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
462486
file.delete();
463487
}
464488
}
465-
466489
File diffFile = new File(outPath + differenceImagePrefix);
467490
if (diffFile.exists()) {
468491
diffFile.delete();
@@ -499,38 +522,23 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
499522
init(outPath + ignoredAreasPrefix + outPdfName, outPath + ignoredAreasPrefix + cmpPdfName);
500523
}
501524

525+
String cmpPdfTempCopy = null;
526+
String replacementImagesDirectory = null;
527+
String outPdfTempCopy = null;
502528
if (targetDir.exists()) {
503-
String gsParams = this.gsParams.replace("<outputfile>", outPath + cmpImage).replace("<inputfile>", cmpPdf);
504-
Process p = runProcess(gsExec , gsParams);
505-
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
506-
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
529+
replacementImagesDirectory = CompareToolUtil.createTempDirectory(tempFilePrefix);
530+
cmpPdfTempCopy = CompareToolUtil.createTempCopy(cmpPdf, tempFilePrefix, null);
531+
outPdfTempCopy = CompareToolUtil.createTempCopy(outPdf, tempFilePrefix, null);
532+
int exitValue = runGhostscriptAndGetExitCode(cmpPdfTempCopy, CompareToolUtil.buildPath(replacementImagesDirectory,
533+
new String[]{"cmp_" + tempFilePrefix + pageNumberPattern + "." + renderedImageExtension}));
507534
String line;
508-
while ((line = bri.readLine()) != null) {
509-
System.out.println(line);
510-
}
511-
bri.close();
512-
while ((line = bre.readLine()) != null) {
513-
System.out.println(line);
514-
}
515-
bre.close();
516-
if (p.waitFor() == 0) {
517-
gsParams = this.gsParams.replace("<outputfile>", outPath + outImage).replace("<inputfile>", outPdf);
518-
p = runProcess(gsExec , gsParams);
519-
bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
520-
bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
521-
while ((line = bri.readLine()) != null) {
522-
System.out.println(line);
523-
}
524-
bri.close();
525-
while ((line = bre.readLine()) != null) {
526-
System.out.println(line);
527-
}
528-
bre.close();
529-
int exitValue = p.waitFor();
530-
535+
if (exitValue == 0) {
536+
exitValue = runGhostscriptAndGetExitCode(outPdfTempCopy, CompareToolUtil.buildPath(replacementImagesDirectory,
537+
new String[]{tempFilePrefix + pageNumberPattern + "." + renderedImageExtension}));
531538
if (exitValue == 0) {
532-
imageFiles = targetDir.listFiles(new PngFileFilter());
533-
cmpImageFiles = targetDir.listFiles(new CmpPngFileFilter());
539+
File tempTargetDir = new File(replacementImagesDirectory);
540+
imageFiles = tempTargetDir.listFiles(new PngFileFilter());
541+
cmpImageFiles = tempTargetDir.listFiles(new CmpPngFileFilter());
534542
boolean bUnexpectedNumberOfPages = false;
535543
if (imageFiles.length != cmpImageFiles.length) {
536544
bUnexpectedNumberOfPages = true;
@@ -543,6 +551,10 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
543551
Arrays.sort(cmpImageFiles, new ImageNameComparator());
544552
String differentPagesFail = null;
545553
for (int i = 0; i < cnt; i++) {
554+
CompareToolUtil.copy(imageFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
555+
new String[]{outPdfName + "-" + (i + 1) + "." + renderedImageExtension}));
556+
CompareToolUtil.copy(cmpImageFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
557+
new String[]{"cmp_" + outPdfName + "-" + (i + 1) + "." + renderedImageExtension}));
546558
if (equalPages != null && equalPages.contains(i))
547559
continue;
548560
System.out.print("Comparing page " + Integer.toString(i + 1) + " (" + imageFiles[i].getAbsolutePath() + ")...");
@@ -552,15 +564,20 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
552564
is1.close();
553565
is2.close();
554566
if (!cmpResult) {
555-
if (compareExec != null && new File(compareExec).exists()) {
556-
String compareParams = this.compareParams.replace("<image1>", imageFiles[i].getAbsolutePath()).replace("<image2>", cmpImageFiles[i].getAbsolutePath()).replace("<difference>", outPath + differenceImagePrefix + Integer.toString(i + 1) + ".png");
557-
p = runProcess(compareExec , compareParams);
558-
bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
567+
if (compareExec != null) {
568+
String compareParams = this.compareParams.replace("<image1>", imageFiles[i].getAbsolutePath()).replace("<image2>",
569+
cmpImageFiles[i].getAbsolutePath()).replace("<difference>",
570+
CompareToolUtil.buildPath(replacementImagesDirectory, new String[]{ "diff" +
571+
(i + 1) + "." + renderedImageExtension}));
572+
573+
Process p = CompareToolUtil.runProcess(compareExec , compareParams);
574+
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
559575
while ((line = bre.readLine()) != null) {
560576
System.out.println(line);
561577
}
562578
bre.close();
563579
int cmpExitValue = p.waitFor();
580+
564581
if (cmpExitValue == 0) {
565582
if (differentPagesFail == null) {
566583
differentPagesFail = differentPages.replace("<filename>", outPdf).replace("<pagenumber>", Integer.toString(i + 1));
@@ -581,8 +598,17 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
581598
} else {
582599
System.out.println("done.");
583600
}
601+
CompareToolUtil.removeFiles(new String[] {imageFiles[i].getAbsolutePath(), cmpImageFiles[i].getAbsolutePath()});
602+
}
603+
File[] diffFiles = tempTargetDir.listFiles();
604+
for (int i = 0; i < diffFiles.length; i++) {
605+
System.out.println(targetDir.getAbsolutePath());
606+
CompareToolUtil.copy(diffFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
607+
new String[]{differenceImagePrefix + "-" + (i + 1) + "." + renderedImageExtension}));
608+
diffFiles[i].delete();
584609
}
585-
if (differentPagesFail != null) {
610+
tempTargetDir.delete();
611+
if (differentPagesFail != null) {
586612
return differentPagesFail;
587613
} else {
588614
if (bUnexpectedNumberOfPages)
@@ -597,20 +623,27 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
597623
} else {
598624
return cannotOpenTargetDirectory.replace("<filename>", outPdf);
599625
}
600-
601626
return null;
602627
}
603628

604-
private Process runProcess(String execPath, String params) throws IOException, InterruptedException {
605-
StringTokenizer st = new StringTokenizer(params);
606-
String[] cmdArray = new String[st.countTokens() + 1];
607-
cmdArray[0] = execPath;
608-
for (int i = 1; st.hasMoreTokens(); ++i)
609-
cmdArray[i] = st.nextToken();
610-
611-
Process p = Runtime.getRuntime().exec(cmdArray);
612-
613-
return p;
629+
private int runGhostscriptAndGetExitCode(String replacementPdf, String replacementImagesDirectory)
630+
throws IOException, InterruptedException {
631+
String gsParams = this.gsParams.replace("<outputfile>", replacementImagesDirectory).
632+
replace("<inputfile>", replacementPdf);
633+
Process p = CompareToolUtil.runProcess(gsExec , gsParams);
634+
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
635+
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
636+
String line;
637+
while ((line = bri.readLine()) != null) {
638+
System.out.println(line);
639+
}
640+
bri.close();
641+
while ((line = bre.readLine()) != null) {
642+
System.out.println(line);
643+
}
644+
bre.close();
645+
int exitValue = p.waitFor();
646+
return exitValue;
614647
}
615648

616649
public String compare(String outPdf, String cmpPdf, String outPath, String differenceImagePrefix, Map<Integer, List<Rectangle>> ignoredAreas) throws IOException, InterruptedException, DocumentException {
@@ -1367,9 +1400,12 @@ private void init(String outPdf, String cmpPdf) {
13671400
this.cmpPdf = cmpPdf;
13681401
outPdfName = new File(outPdf).getName();
13691402
cmpPdfName = new File(cmpPdf).getName();
1370-
outImage = outPdfName + "-%03d.png";
1371-
if (cmpPdfName.startsWith("cmp_")) cmpImage = cmpPdfName + "-%03d.png";
1372-
else cmpImage = "cmp_" + cmpPdfName + "-%03d.png";
1403+
outImage = outPdfName + pageNumberPattern + "." + renderedImageExtension;
1404+
if (cmpPdfName.startsWith("cmp_")) {
1405+
cmpImage = cmpPdfName + pageNumberPattern + "." + renderedImageExtension ;
1406+
} else {
1407+
cmpImage = "cmp_" + cmpPdfName + pageNumberPattern + "." + renderedImageExtension;
1408+
}
13731409
}
13741410

13751411
private boolean compareStreams(InputStream is1, InputStream is2) throws IOException {
@@ -1396,7 +1432,7 @@ public boolean accept(File pathname) {
13961432
String ap = pathname.getAbsolutePath();
13971433
boolean b1 = ap.endsWith(".png");
13981434
boolean b2 = ap.contains("cmp_");
1399-
return b1 && !b2 && ap.contains(outPdfName);
1435+
return b1 && !b2;
14001436
}
14011437
}
14021438

@@ -1405,7 +1441,7 @@ public boolean accept(File pathname) {
14051441
String ap = pathname.getAbsolutePath();
14061442
boolean b1 = ap.endsWith(".png");
14071443
boolean b2 = ap.contains("cmp_");
1408-
return b1 && b2 && ap.contains(cmpPdfName);
1444+
return b1 && b2;
14091445
}
14101446
}
14111447

@@ -1500,6 +1536,4 @@ public InputSource resolveEntity(String publicId, String systemId) throws SAXExc
15001536
return new InputSource(new StringReader(""));
15011537
}
15021538
}
1503-
1504-
15051539
}

0 commit comments

Comments
 (0)