Skip to content

Commit 5fc4165

Browse files
Fix PdfLayer#getIntents in case of multiple intents; add new PdfLayer tests
Also implement new comparison method of CompareTool for more local checks. DEVSIX-3117
1 parent 32a1f78 commit 5fc4165

23 files changed

+626
-160
lines changed

kernel/src/main/java/com/itextpdf/kernel/pdf/layer/PdfLayer.java

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -55,8 +55,8 @@ This file is part of the iText (R) project.
5555
import com.itextpdf.kernel.pdf.PdfString;
5656

5757
import java.util.ArrayList;
58-
import java.util.Arrays;
5958
import java.util.Collection;
59+
import java.util.Collections;
6060
import java.util.List;
6161

6262
/**
@@ -226,18 +226,25 @@ public void setOnPanel(boolean onPanel) {
226226

227227
/**
228228
* Gets a collection of current intents specified for this layer.
229-
* The default value is PdfName.View, so it will be the only element of the
230-
* resultant colletion if no intents are currently specified.
229+
* The default value is {@link PdfName#View}, so it will be the only element of the
230+
* resultant collection if no intents are currently specified.
231231
* @return the collection of intents.
232232
*/
233233
public Collection<PdfName> getIntents() {
234234
final PdfObject intent = getPdfObject().get(PdfName.Intent);
235235
if (intent instanceof PdfName)
236-
return Arrays.asList((PdfName) intent);
236+
return Collections.singletonList((PdfName) intent);
237237
else if (intent instanceof PdfArray) {
238-
return (Collection<PdfName>) intent;
238+
PdfArray intentArr = (PdfArray) intent;
239+
Collection<PdfName> intentsCollection = new ArrayList<>(intentArr.size());
240+
for (PdfObject i : intentArr) {
241+
if (i instanceof PdfName) {
242+
intentsCollection.add((PdfName) i);
243+
}
244+
}
245+
return intentsCollection;
239246
}
240-
return Arrays.asList(PdfName.View);
247+
return Collections.singletonList(PdfName.View);
241248
}
242249

243250
/**
@@ -249,7 +256,7 @@ public void setIntents(List<PdfName> intents) {
249256
getPdfObject().remove(PdfName.Intent);
250257
} else if (intents.size() == 1) {
251258
getPdfObject().put(PdfName.Intent, intents.get(0));
252-
} else if (intents.size() > 1) {
259+
} else { // intents.size() > 1
253260
PdfArray array = new PdfArray();
254261
for (PdfName intent : intents) {
255262
array.add(intent);

kernel/src/main/java/com/itextpdf/kernel/pdf/layer/PdfOCProperties.java

Lines changed: 43 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,6 @@ This file is part of the iText (R) project.
5252
import com.itextpdf.kernel.pdf.PdfObject;
5353
import com.itextpdf.kernel.pdf.PdfObjectWrapper;
5454
import com.itextpdf.kernel.pdf.PdfString;
55-
5655
import java.util.ArrayList;
5756
import java.util.HashSet;
5857
import java.util.List;
@@ -63,38 +62,17 @@ This file is part of the iText (R) project.
6362
/**
6463
* This class represents /OCProperties entry if pdf catalog and manages
6564
* the layers of the pdf document.
66-
*
67-
* <br><br>
65+
* <p>
6866
* To be able to be wrapped with this {@link PdfObjectWrapper} the {@link PdfObject}
6967
* must be indirect.
7068
*/
7169
public class PdfOCProperties extends PdfObjectWrapper<PdfDictionary> {
7270

71+
static final String OC_CONFIG_NAME_PATTERN = "OCConfigName";
72+
7373
private static final long serialVersionUID = 1137977454824741350L;
7474
private List<PdfLayer> layers = new ArrayList<>();
7575

76-
/**
77-
* Gets the order of the layers in which they will be displayed in the layer view panel,
78-
* including nesting.
79-
*/
80-
private static void getOCGOrder(PdfArray order, PdfLayer layer) {
81-
if (!layer.isOnPanel())
82-
return;
83-
if (layer.getTitle() == null)
84-
order.add(layer.getPdfObject().getIndirectReference());
85-
List<PdfLayer> children = layer.getChildren();
86-
if (children == null)
87-
return;
88-
PdfArray kids = new PdfArray();
89-
if (layer.getTitle() != null)
90-
kids.add(new PdfString(layer.getTitle(), PdfEncodings.UNICODE_BIG));
91-
for (PdfLayer child : children) {
92-
getOCGOrder(kids, child);
93-
}
94-
if (kids.size() > 0)
95-
order.add(kids);
96-
}
97-
9876
/**
9977
* Creates a new PdfOCProperties instance.
10078
*
@@ -224,24 +202,6 @@ public PdfObject fillDictionary() {
224202
return getPdfObject();
225203
}
226204

227-
private String createUniqueName() {
228-
int uniqueID = 0;
229-
Set<String> usedNames = new HashSet<>();
230-
PdfArray configs = getPdfObject().getAsArray(PdfName.Configs);
231-
if (null != configs) {
232-
for (int i = 0; i < configs.size(); i++) {
233-
PdfDictionary alternateDictionary = configs.getAsDictionary(i);
234-
if (null != alternateDictionary && alternateDictionary.containsKey(PdfName.Name)) {
235-
usedNames.add(alternateDictionary.getAsString(PdfName.Name).toUnicodeString());
236-
}
237-
}
238-
}
239-
while (usedNames.contains("OCConfigName" + uniqueID)) {
240-
uniqueID++;
241-
}
242-
return "OCConfigName" + uniqueID;
243-
}
244-
245205
@Override
246206
public void flush() {
247207
fillDictionary();
@@ -276,6 +236,28 @@ protected PdfDocument getDocument() {
276236
return getPdfObject().getIndirectReference().getDocument();
277237
}
278238

239+
/**
240+
* Gets the order of the layers in which they will be displayed in the layer view panel,
241+
* including nesting.
242+
*/
243+
private static void getOCGOrder(PdfArray order, PdfLayer layer) {
244+
if (!layer.isOnPanel())
245+
return;
246+
if (layer.getTitle() == null)
247+
order.add(layer.getPdfObject().getIndirectReference());
248+
List<PdfLayer> children = layer.getChildren();
249+
if (children == null)
250+
return;
251+
PdfArray kids = new PdfArray();
252+
if (layer.getTitle() != null)
253+
kids.add(new PdfString(layer.getTitle(), PdfEncodings.UNICODE_BIG));
254+
for (PdfLayer child : children) {
255+
getOCGOrder(kids, child);
256+
}
257+
if (kids.size() > 0)
258+
order.add(kids);
259+
}
260+
279261
/**
280262
* Populates the /AS entry in the /D dictionary.
281263
*/
@@ -386,4 +368,22 @@ private void readOrderFromDictionary(PdfLayer parent, PdfArray orderArray, Map<P
386368
}
387369
}
388370
}
371+
372+
private String createUniqueName() {
373+
int uniqueID = 0;
374+
Set<String> usedNames = new HashSet<>();
375+
PdfArray configs = getPdfObject().getAsArray(PdfName.Configs);
376+
if (null != configs) {
377+
for (int i = 0; i < configs.size(); i++) {
378+
PdfDictionary alternateDictionary = configs.getAsDictionary(i);
379+
if (null != alternateDictionary && alternateDictionary.containsKey(PdfName.Name)) {
380+
usedNames.add(alternateDictionary.getAsString(PdfName.Name).toUnicodeString());
381+
}
382+
}
383+
}
384+
while (usedNames.contains(OC_CONFIG_NAME_PATTERN + uniqueID)) {
385+
uniqueID++;
386+
}
387+
return OC_CONFIG_NAME_PATTERN + uniqueID;
388+
}
389389
}

kernel/src/main/java/com/itextpdf/kernel/utils/CompareTool.java

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -546,6 +546,62 @@ public boolean compareDictionaries(PdfDictionary outDict, PdfDictionary cmpDict)
546546
return compareDictionariesExtended(outDict, cmpDict, null, null);
547547
}
548548

549+
/**
550+
* Recursively compares structures of two corresponding dictionaries from out and cmp PDF documents. You can roughly
551+
* imagine it as depth-first traversal of the two trees that represent pdf objects structure of the documents.
552+
* <p>
553+
* Both out and cmp {@link PdfDictionary} shall have indirect references.
554+
* <p>
555+
* By default page dictionaries are excluded from the comparison when met and are instead compared in a special manner,
556+
* simply comparing their page numbers. This behavior can be disabled by calling {@link #disableCachedPagesComparison()}.
557+
* <p>
558+
* For more explanations about what is outPdf and cmpPdf see last paragraph of the {@link CompareTool}
559+
* class description.
560+
*
561+
* @param outDict an indirect {@link PdfDictionary} from the output file, which is to be compared to cmp-file dictionary.
562+
* @param cmpDict an indirect {@link PdfDictionary} from the cmp-file file, which is to be compared to output file dictionary.
563+
* @return {@link CompareResult} instance containing differences between the two dictionaries,
564+
* or {@code null} if dictionaries are equal.
565+
*/
566+
public CompareResult compareDictionariesStructure(PdfDictionary outDict, PdfDictionary cmpDict) {
567+
return compareDictionariesStructure(outDict, cmpDict, null);
568+
}
569+
570+
/**
571+
* Recursively compares structures of two corresponding dictionaries from out and cmp PDF documents. You can roughly
572+
* imagine it as depth-first traversal of the two trees that represent pdf objects structure of the documents.
573+
* <p>
574+
* Both out and cmp {@link PdfDictionary} shall have indirect references.
575+
* <p>
576+
* By default page dictionaries are excluded from the comparison when met and are instead compared in a special manner,
577+
* simply comparing their page numbers. This behavior can be disabled by calling {@link #disableCachedPagesComparison()}.
578+
* <p>
579+
* For more explanations about what is outPdf and cmpPdf see last paragraph of the {@link CompareTool}
580+
* class description.
581+
*
582+
* @param outDict an indirect {@link PdfDictionary} from the output file, which is to be compared to cmp-file dictionary.
583+
* @param cmpDict an indirect {@link PdfDictionary} from the cmp-file file, which is to be compared to output file dictionary.
584+
* @param excludedKeys a {@link Set} of names that designate entries from {@code outDict} and {@code cmpDict} dictionaries
585+
* which are to be skipped during comparison.
586+
* @return {@link CompareResult} instance containing differences between the two dictionaries,
587+
* or {@code null} if dictionaries are equal.
588+
*/
589+
public CompareResult compareDictionariesStructure(PdfDictionary outDict, PdfDictionary cmpDict, Set<PdfName> excludedKeys) {
590+
if (outDict.getIndirectReference() == null || cmpDict.getIndirectReference() == null) {
591+
throw new IllegalArgumentException("The 'outDict' and 'cmpDict' objects shall have indirect references.");
592+
}
593+
594+
CompareResult compareResult = new CompareResult(compareByContentErrorsLimit);
595+
CompareTool.ObjectPath currentPath = new ObjectPath(cmpDict.getIndirectReference(), outDict.getIndirectReference());
596+
if (!compareDictionariesExtended(outDict, cmpDict, currentPath, compareResult, excludedKeys)) {
597+
assert !compareResult.isOk();
598+
System.out.println(compareResult.getReport());
599+
return compareResult;
600+
}
601+
assert compareResult.isOk();
602+
return null;
603+
}
604+
549605
/**
550606
* Simple method that compares two given PdfStreams by content. This is "deep" comparing, which means that all
551607
* nested objects are also compared by content.

kernel/src/test/java/com/itextpdf/kernel/pdf/PdfLayerTest.java

Lines changed: 0 additions & 103 deletions
This file was deleted.

0 commit comments

Comments
 (0)