Skip to content

Commit

Permalink
Improve input processing for ImageMagick and Ghostscript
Browse files Browse the repository at this point in the history
DEV-2010
  • Loading branch information
Evgeniy Prudnikov committed Feb 4, 2022
1 parent 88737e7 commit ce8bbac
Show file tree
Hide file tree
Showing 15 changed files with 427 additions and 60 deletions.
150 changes: 92 additions & 58 deletions itext/src/main/java/com/itextpdf/testutils/CompareTool.java
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,25 @@
import com.itextpdf.text.Meta;
import com.itextpdf.text.Rectangle;
import com.itextpdf.text.io.RandomAccessSourceFactory;
import com.itextpdf.text.pdf.*;
import com.itextpdf.text.pdf.PRIndirectReference;
import com.itextpdf.text.pdf.PRStream;
import com.itextpdf.text.pdf.PRTokeniser;
import com.itextpdf.text.pdf.PdfAnnotation;
import com.itextpdf.text.pdf.PdfArray;
import com.itextpdf.text.pdf.PdfBoolean;
import com.itextpdf.text.pdf.PdfContentByte;
import com.itextpdf.text.pdf.PdfContentParser;
import com.itextpdf.text.pdf.PdfDictionary;
import com.itextpdf.text.pdf.PdfIndirectReference;
import com.itextpdf.text.pdf.PdfLiteral;
import com.itextpdf.text.pdf.PdfName;
import com.itextpdf.text.pdf.PdfNumber;
import com.itextpdf.text.pdf.PdfObject;
import com.itextpdf.text.pdf.PdfReader;
import com.itextpdf.text.pdf.PdfStamper;
import com.itextpdf.text.pdf.PdfString;
import com.itextpdf.text.pdf.RandomAccessFileOrArray;
import com.itextpdf.text.pdf.RefKey;
import com.itextpdf.text.pdf.parser.ContentByteUtils;
import com.itextpdf.text.pdf.parser.ImageRenderInfo;
import com.itextpdf.text.pdf.parser.InlineImageInfo;
Expand Down Expand Up @@ -89,9 +107,8 @@
import java.util.Map;
import java.util.Set;
import java.util.Stack;
import java.util.StringTokenizer;
import java.util.TreeSet;

import java.util.regex.Pattern;
import javax.xml.XMLConstants;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
Expand All @@ -102,7 +119,6 @@
import javax.xml.transform.TransformerFactory;
import javax.xml.transform.dom.DOMSource;
import javax.xml.transform.stream.StreamResult;

import org.w3c.dom.Document;
import org.w3c.dom.Element;
import org.w3c.dom.Node;
Expand Down Expand Up @@ -392,9 +408,17 @@ public void writeReportToXml(OutputStream stream) throws ParserConfigurationExce

private String gsExec;
private String compareExec;
private final String gsParams = " -dNOPAUSE -dBATCH -sDEVICE=png16m -r150 -sOutputFile=<outputfile> <inputfile>";
private static final String renderedImageExtension = "png";
private static final String pageNumberPattern = "%03d";
private static final Pattern pageListRegexp = Pattern.compile("^(\\d+,)*\\d+$");
private static final String tempFilePrefix = "itext_gs_io_temp";


private final String gsParams = " -dNOPAUSE -dBATCH -dSAFER -sDEVICE=" +
renderedImageExtension + "16m -r150 -sOutputFile=<outputfile> <inputfile>";
private final String compareParams = " \"<image1>\" \"<image2>\" \"<difference>\"";


static private final String cannotOpenTargetDirectory = "Cannot open target directory for <filename>.";
static private final String gsFailed = "GhostScript failed for <filename>.";
static private final String unexpectedNumberOfPages = "Unexpected number of pages for <filename>.";
Expand Down Expand Up @@ -462,7 +486,6 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
file.delete();
}
}

File diffFile = new File(outPath + differenceImagePrefix);
if (diffFile.exists()) {
diffFile.delete();
Expand Down Expand Up @@ -499,38 +522,23 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
init(outPath + ignoredAreasPrefix + outPdfName, outPath + ignoredAreasPrefix + cmpPdfName);
}

String cmpPdfTempCopy = null;
String replacementImagesDirectory = null;
String outPdfTempCopy = null;
if (targetDir.exists()) {
String gsParams = this.gsParams.replace("<outputfile>", outPath + cmpImage).replace("<inputfile>", cmpPdf);
Process p = runProcess(gsExec , gsParams);
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
replacementImagesDirectory = CompareToolUtil.createTempDirectory(tempFilePrefix);
cmpPdfTempCopy = CompareToolUtil.createTempCopy(cmpPdf, tempFilePrefix, null);
outPdfTempCopy = CompareToolUtil.createTempCopy(outPdf, tempFilePrefix, null);
int exitValue = runGhostscriptAndGetExitCode(cmpPdfTempCopy, CompareToolUtil.buildPath(replacementImagesDirectory,
new String[]{"cmp_" + tempFilePrefix + pageNumberPattern + "." + renderedImageExtension}));
String line;
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
if (p.waitFor() == 0) {
gsParams = this.gsParams.replace("<outputfile>", outPath + outImage).replace("<inputfile>", outPdf);
p = runProcess(gsExec , gsParams);
bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
int exitValue = p.waitFor();

if (exitValue == 0) {
exitValue = runGhostscriptAndGetExitCode(outPdfTempCopy, CompareToolUtil.buildPath(replacementImagesDirectory,
new String[]{tempFilePrefix + pageNumberPattern + "." + renderedImageExtension}));
if (exitValue == 0) {
imageFiles = targetDir.listFiles(new PngFileFilter());
cmpImageFiles = targetDir.listFiles(new CmpPngFileFilter());
File tempTargetDir = new File(replacementImagesDirectory);
imageFiles = tempTargetDir.listFiles(new PngFileFilter());
cmpImageFiles = tempTargetDir.listFiles(new CmpPngFileFilter());
boolean bUnexpectedNumberOfPages = false;
if (imageFiles.length != cmpImageFiles.length) {
bUnexpectedNumberOfPages = true;
Expand All @@ -543,6 +551,10 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
Arrays.sort(cmpImageFiles, new ImageNameComparator());
String differentPagesFail = null;
for (int i = 0; i < cnt; i++) {
CompareToolUtil.copy(imageFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
new String[]{outPdfName + "-" + (i + 1) + "." + renderedImageExtension}));
CompareToolUtil.copy(cmpImageFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
new String[]{"cmp_" + outPdfName + "-" + (i + 1) + "." + renderedImageExtension}));
if (equalPages != null && equalPages.contains(i))
continue;
System.out.print("Comparing page " + Integer.toString(i + 1) + " (" + imageFiles[i].getAbsolutePath() + ")...");
Expand All @@ -552,15 +564,20 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
is1.close();
is2.close();
if (!cmpResult) {
if (compareExec != null && new File(compareExec).exists()) {
String compareParams = this.compareParams.replace("<image1>", imageFiles[i].getAbsolutePath()).replace("<image2>", cmpImageFiles[i].getAbsolutePath()).replace("<difference>", outPath + differenceImagePrefix + Integer.toString(i + 1) + ".png");
p = runProcess(compareExec , compareParams);
bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
if (compareExec != null) {
String compareParams = this.compareParams.replace("<image1>", imageFiles[i].getAbsolutePath()).replace("<image2>",
cmpImageFiles[i].getAbsolutePath()).replace("<difference>",
CompareToolUtil.buildPath(replacementImagesDirectory, new String[]{ "diff" +
(i + 1) + "." + renderedImageExtension}));

Process p = CompareToolUtil.runProcess(compareExec , compareParams);
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
int cmpExitValue = p.waitFor();

if (cmpExitValue == 0) {
if (differentPagesFail == null) {
differentPagesFail = differentPages.replace("<filename>", outPdf).replace("<pagenumber>", Integer.toString(i + 1));
Expand All @@ -581,8 +598,17 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
} else {
System.out.println("done.");
}
CompareToolUtil.removeFiles(new String[] {imageFiles[i].getAbsolutePath(), cmpImageFiles[i].getAbsolutePath()});
}
File[] diffFiles = tempTargetDir.listFiles();
for (int i = 0; i < diffFiles.length; i++) {
System.out.println(targetDir.getAbsolutePath());
CompareToolUtil.copy(diffFiles[i].getAbsolutePath(), CompareToolUtil.buildPath(targetDir.getAbsolutePath(),
new String[]{differenceImagePrefix + "-" + (i + 1) + "." + renderedImageExtension}));
diffFiles[i].delete();
}
if (differentPagesFail != null) {
tempTargetDir.delete();
if (differentPagesFail != null) {
return differentPagesFail;
} else {
if (bUnexpectedNumberOfPages)
Expand All @@ -597,20 +623,27 @@ private String compare(String outPath, String differenceImagePrefix, Map<Integer
} else {
return cannotOpenTargetDirectory.replace("<filename>", outPdf);
}

return null;
}

private Process runProcess(String execPath, String params) throws IOException, InterruptedException {
StringTokenizer st = new StringTokenizer(params);
String[] cmdArray = new String[st.countTokens() + 1];
cmdArray[0] = execPath;
for (int i = 1; st.hasMoreTokens(); ++i)
cmdArray[i] = st.nextToken();

Process p = Runtime.getRuntime().exec(cmdArray);

return p;
private int runGhostscriptAndGetExitCode(String replacementPdf, String replacementImagesDirectory)
throws IOException, InterruptedException {
String gsParams = this.gsParams.replace("<outputfile>", replacementImagesDirectory).
replace("<inputfile>", replacementPdf);
Process p = CompareToolUtil.runProcess(gsExec , gsParams);
BufferedReader bri = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader bre = new BufferedReader(new InputStreamReader(p.getErrorStream()));
String line;
while ((line = bri.readLine()) != null) {
System.out.println(line);
}
bri.close();
while ((line = bre.readLine()) != null) {
System.out.println(line);
}
bre.close();
int exitValue = p.waitFor();
return exitValue;
}

public String compare(String outPdf, String cmpPdf, String outPath, String differenceImagePrefix, Map<Integer, List<Rectangle>> ignoredAreas) throws IOException, InterruptedException, DocumentException {
Expand Down Expand Up @@ -1367,9 +1400,12 @@ private void init(String outPdf, String cmpPdf) {
this.cmpPdf = cmpPdf;
outPdfName = new File(outPdf).getName();
cmpPdfName = new File(cmpPdf).getName();
outImage = outPdfName + "-%03d.png";
if (cmpPdfName.startsWith("cmp_")) cmpImage = cmpPdfName + "-%03d.png";
else cmpImage = "cmp_" + cmpPdfName + "-%03d.png";
outImage = outPdfName + pageNumberPattern + "." + renderedImageExtension;
if (cmpPdfName.startsWith("cmp_")) {
cmpImage = cmpPdfName + pageNumberPattern + "." + renderedImageExtension ;
} else {
cmpImage = "cmp_" + cmpPdfName + pageNumberPattern + "." + renderedImageExtension;
}
}

private boolean compareStreams(InputStream is1, InputStream is2) throws IOException {
Expand All @@ -1396,7 +1432,7 @@ public boolean accept(File pathname) {
String ap = pathname.getAbsolutePath();
boolean b1 = ap.endsWith(".png");
boolean b2 = ap.contains("cmp_");
return b1 && !b2 && ap.contains(outPdfName);
return b1 && !b2;
}
}

Expand All @@ -1405,7 +1441,7 @@ public boolean accept(File pathname) {
String ap = pathname.getAbsolutePath();
boolean b1 = ap.endsWith(".png");
boolean b2 = ap.contains("cmp_");
return b1 && b2 && ap.contains(cmpPdfName);
return b1 && b2;
}
}

Expand Down Expand Up @@ -1500,6 +1536,4 @@ public InputSource resolveEntity(String publicId, String systemId) throws SAXExc
return new InputSource(new StringReader(""));
}
}


}
Loading

0 comments on commit ce8bbac

Please sign in to comment.