Skip to content

Commit 8accf34

Browse files
committed
Support universal ToUnicode CMaps
DEVSIX-6147
1 parent b9ec019 commit 8accf34

File tree

11 files changed

+73530
-7
lines changed

11 files changed

+73530
-7
lines changed

font-asian/src/main/resources/com/itextpdf/io/font/cmap/toUnicode/Adobe-CNS1-UCS2

Lines changed: 18303 additions & 0 deletions
Large diffs are not rendered by default.

font-asian/src/main/resources/com/itextpdf/io/font/cmap/toUnicode/Adobe-GB1-UCS2

Lines changed: 14268 additions & 0 deletions
Large diffs are not rendered by default.

font-asian/src/main/resources/com/itextpdf/io/font/cmap/toUnicode/Adobe-Japan1-UCS2

Lines changed: 19160 additions & 0 deletions
Large diffs are not rendered by default.

font-asian/src/main/resources/com/itextpdf/io/font/cmap/toUnicode/Adobe-KR-UCS2

Lines changed: 12436 additions & 0 deletions
Large diffs are not rendered by default.

font-asian/src/main/resources/com/itextpdf/io/font/cmap/toUnicode/Adobe-Korea1-UCS2

Lines changed: 9265 additions & 0 deletions
Large diffs are not rendered by default.

kernel/src/main/java/com/itextpdf/kernel/exceptions/KernelExceptionMessageConstant.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -279,6 +279,7 @@ public final class KernelExceptionMessageConstant {
279279
public static final String ONLY_BMP_CAN_BE_WRAPPED_IN_WMF = "Only BMP can be wrapped in WMF.";
280280
public static final String OPERATOR_EI_NOT_FOUND_AFTER_END_OF_IMAGE_DATA = "Operator EI not found after the end "
281281
+ "of image data.";
282+
public static final String ORDERING_SHOULD_BE_DETERMINED = "Ordering should be determined for CIDFont of Type0 font.";
282283
public static final String PAGE_CANNOT_BE_ADDED_TO_DOCUMENT_BECAUSE_IT_BELONGS_TO_ANOTHER_DOCUMENT =
283284
"The passed page belongs to document {0} (page {1} of the document) and therefore cannot be added "
284285
+ "to this document ({2}).";

kernel/src/main/java/com/itextpdf/kernel/font/FontUtil.java

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ This file is part of the iText (R) project.
2525
import com.itextpdf.io.font.FontCache;
2626
import com.itextpdf.io.font.PdfEncodings;
2727
import com.itextpdf.io.font.cmap.CMapLocationFromBytes;
28+
import com.itextpdf.io.font.cmap.CMapLocationResource;
2829
import com.itextpdf.io.font.cmap.CMapParser;
2930
import com.itextpdf.io.font.cmap.CMapToUnicode;
3031
import com.itextpdf.io.font.cmap.CMapUniCid;
@@ -40,6 +41,8 @@ This file is part of the iText (R) project.
4041
import java.security.SecureRandom;
4142
import java.util.Arrays;
4243
import java.util.HashMap;
44+
import java.util.HashSet;
45+
import java.util.Set;
4346
import org.slf4j.Logger;
4447
import org.slf4j.LoggerFactory;
4548

@@ -48,6 +51,13 @@ public class FontUtil {
4851

4952
private static final HashMap<String, CMapToUnicode> uniMaps = new HashMap<>();
5053

54+
private static final Logger LOGGER = LoggerFactory.getLogger(FontUtil.class);
55+
56+
private static final String UNIVERSAL_CMAP_DIR = "toUnicode/";
57+
58+
private static final Set<String> UNIVERSAL_CMAP_ORDERINGS = new HashSet<>(Arrays.asList(
59+
"CNS1", "GB1", "Japan1", "Korea1", "KR"));
60+
5161
private FontUtil() {}
5262

5363
public static String addRandomSubsetPrefixForFontName(final String fontName) {
@@ -70,8 +80,7 @@ static CMapToUnicode processToUnicode(PdfObject toUnicode) {
7080
cMapToUnicode = new CMapToUnicode();
7181
CMapParser.parseCid("", cMapToUnicode, lb);
7282
} catch (Exception e) {
73-
Logger logger = LoggerFactory.getLogger(CMapToUnicode.class);
74-
logger.error(IoLogMessageConstant.UNKNOWN_ERROR_WHILE_PROCESSING_CMAP);
83+
LOGGER.error(IoLogMessageConstant.UNKNOWN_ERROR_WHILE_PROCESSING_CMAP, e);
7584
cMapToUnicode = CMapToUnicode.EmptyCMapToUnicodeMap;
7685
}
7786
} else if (PdfName.IdentityH.equals(toUnicode)) {
@@ -80,6 +89,21 @@ static CMapToUnicode processToUnicode(PdfObject toUnicode) {
8089
return cMapToUnicode;
8190
}
8291

92+
static CMapToUnicode parseUniversalToUnicodeCMap(String ordering) {
93+
if (!UNIVERSAL_CMAP_ORDERINGS.contains(ordering)) {
94+
return null;
95+
}
96+
String cmapRelPath = UNIVERSAL_CMAP_DIR + "Adobe-" + ordering + "-UCS2";
97+
CMapToUnicode cMapToUnicode = new CMapToUnicode();
98+
try {
99+
CMapParser.parseCid(cmapRelPath, cMapToUnicode, new CMapLocationResource());
100+
} catch (Exception e) {
101+
LOGGER.error(IoLogMessageConstant.UNKNOWN_ERROR_WHILE_PROCESSING_CMAP, e);
102+
return null;
103+
}
104+
return cMapToUnicode;
105+
}
106+
83107
static CMapToUnicode getToUnicodeFromUniMap(String uniMap) {
84108
if (uniMap == null)
85109
return null;

kernel/src/main/java/com/itextpdf/kernel/font/PdfType0Font.java

Lines changed: 15 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -142,13 +142,24 @@ public class PdfType0Font extends PdfFont {
142142
newFont = false;
143143
PdfDictionary cidFont = fontDictionary.getAsArray(PdfName.DescendantFonts).getAsDictionary(0);
144144
PdfObject cmap = fontDictionary.get(PdfName.Encoding);
145+
146+
String ordering = getOrdering(cidFont);
147+
if(ordering == null) {
148+
throw new PdfException(KernelExceptionMessageConstant.ORDERING_SHOULD_BE_DETERMINED);
149+
}
150+
CMapToUnicode toUnicodeCMap;
145151
PdfObject toUnicode = fontDictionary.get(PdfName.ToUnicode);
146-
CMapToUnicode toUnicodeCMap = FontUtil.processToUnicode(toUnicode);
152+
if (toUnicode == null) {
153+
toUnicodeCMap = FontUtil.parseUniversalToUnicodeCMap(ordering);
154+
} else {
155+
toUnicodeCMap = FontUtil.processToUnicode(toUnicode);
156+
}
157+
147158
if (cmap.isName() && (PdfEncodings.IDENTITY_H.equals(((PdfName) cmap).getValue()) ||
148159
PdfEncodings.IDENTITY_V.equals(((PdfName) cmap).getValue()))) {
160+
149161
if (toUnicodeCMap == null) {
150-
String uniMap = getUniMapFromOrdering(getOrdering(cidFont),
151-
PdfEncodings.IDENTITY_H.equals(((PdfName) cmap).getValue()));
162+
String uniMap = getUniMapFromOrdering(ordering, PdfEncodings.IDENTITY_H.equals(((PdfName) cmap).getValue()));
152163
toUnicodeCMap = FontUtil.getToUnicodeFromUniMap(uniMap);
153164
if (toUnicodeCMap == null) {
154165
toUnicodeCMap = FontUtil.getToUnicodeFromUniMap(PdfEncodings.IDENTITY_H);
@@ -162,7 +173,7 @@ public class PdfType0Font extends PdfFont {
162173
embedded = ((IDocFontProgram) fontProgram).getFontFile() != null;
163174
} else {
164175
String cidFontName = cidFont.getAsName(PdfName.BaseFont).getValue();
165-
String uniMap = getUniMapFromOrdering(getOrdering(cidFont), true);
176+
String uniMap = getUniMapFromOrdering(ordering, true);
166177
if (uniMap != null && uniMap.startsWith("Uni") && CidFontProperties.isCidFont(cidFontName, uniMap)) {
167178
try {
168179
fontProgram = FontProgramFactory.createFont(cidFontName);
Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
package com.itextpdf.kernel.font;
2+
3+
import com.itextpdf.io.font.cmap.CMapToUnicode;
4+
import com.itextpdf.io.logs.IoLogMessageConstant;
5+
import com.itextpdf.io.source.ByteArrayOutputStream;
6+
import com.itextpdf.kernel.pdf.PdfDocument;
7+
import com.itextpdf.kernel.pdf.PdfStream;
8+
import com.itextpdf.kernel.pdf.PdfWriter;
9+
import com.itextpdf.test.ExtendedITextTest;
10+
import com.itextpdf.test.LogLevelConstants;
11+
import com.itextpdf.test.annotations.LogMessage;
12+
import com.itextpdf.test.annotations.LogMessages;
13+
import com.itextpdf.test.annotations.type.UnitTest;
14+
15+
import org.junit.Assert;
16+
import org.junit.Test;
17+
import org.junit.experimental.categories.Category;
18+
19+
@Category(UnitTest.class)
20+
public class FontUtilTest extends ExtendedITextTest {
21+
@Test
22+
public void parseUniversalNotExistedCMapTest() {
23+
Assert.assertNull(FontUtil.parseUniversalToUnicodeCMap("NotExisted"));
24+
}
25+
26+
@Test
27+
@LogMessages(messages = {
28+
@LogMessage(messageTemplate = IoLogMessageConstant.UNKNOWN_ERROR_WHILE_PROCESSING_CMAP, logLevel = LogLevelConstants.ERROR)
29+
})
30+
public void processInvalidToUnicodeTest() {
31+
PdfStream toUnicode = new PdfStream();
32+
try (PdfDocument pdfDocument = new PdfDocument(new PdfWriter(new ByteArrayOutputStream()))) {
33+
toUnicode.makeIndirect(pdfDocument);
34+
toUnicode.flush();
35+
final CMapToUnicode cmap = FontUtil.processToUnicode(toUnicode);
36+
Assert.assertNotNull(cmap);
37+
Assert.assertFalse(cmap.hasByteMappings());
38+
}
39+
}
40+
}

kernel/src/test/java/com/itextpdf/kernel/font/PdfType0FontTest.java

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ This file is part of the iText (R) project.
2828
import com.itextpdf.io.font.otf.Glyph;
2929
import com.itextpdf.kernel.exceptions.KernelExceptionMessageConstant;
3030
import com.itextpdf.kernel.exceptions.PdfException;
31+
import com.itextpdf.kernel.pdf.PdfArray;
3132
import com.itextpdf.kernel.pdf.PdfDictionary;
3233
import com.itextpdf.kernel.pdf.PdfDocument;
3334
import com.itextpdf.kernel.pdf.PdfName;
@@ -128,4 +129,18 @@ public void getUniMapFromOrderingTest() {
128129
Assert.assertEquals("Identity-H", PdfType0Font.getUniMapFromOrdering("Identity", true));
129130
Assert.assertEquals("Identity-V", PdfType0Font.getUniMapFromOrdering("Identity", false));
130131
}
132+
133+
@Test
134+
public void descendantCidFontWithoutOrderingTest() {
135+
PdfDictionary fontDict = new PdfDictionary();
136+
PdfArray descendantFonts = new PdfArray();
137+
PdfDictionary descendantFont = new PdfDictionary();
138+
descendantFont.put(PdfName.CIDSystemInfo, new PdfDictionary());
139+
descendantFonts.add(descendantFont);
140+
fontDict.put(PdfName.DescendantFonts, descendantFonts);
141+
142+
143+
Exception e = Assert.assertThrows(PdfException.class, () -> new PdfType0Font(fontDict));
144+
Assert.assertEquals(KernelExceptionMessageConstant.ORDERING_SHOULD_BE_DETERMINED, e.getMessage());
145+
}
131146
}

0 commit comments

Comments
 (0)