You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@xmlgraphics.apache.org by ss...@apache.org on 2025/07/21 07:12:16 UTC
(xmlgraphics-fop-pdf-images) branch main updated: FOP-3265: Remap glyphs for gid conflict
This is an automated email from the ASF dual-hosted git repository.
ssteiner pushed a commit to branch main
in repository https://gitbox.apache.org/repos/asf/xmlgraphics-fop-pdf-images.git
The following commit(s) were added to refs/heads/main by this push:
new c312e15 FOP-3265: Remap glyphs for gid conflict
c312e15 is described below
commit c312e15ce7a19f710e2ec13e8ace6d80ab33e7b7
Author: Simon Steiner <ss...@apache.org>
AuthorDate: Mon Jul 21 08:12:04 2025 +0100
FOP-3265: Remap glyphs for gid conflict
---
.../render/pdf/pdfbox/FOPPDFSingleByteFont.java | 11 +--
.../apache/fop/render/pdf/pdfbox/MergeTTFonts.java | 15 ++--
.../pdfbox/FOPPDFSingleMultiByteFontTestCase.java | 92 ++++++++++++---------
.../apache/fop/render/pdf/pdfbox/ttsubset18.pdf | Bin 0 -> 20790 bytes
.../apache/fop/render/pdf/pdfbox/ttsubset19.pdf | Bin 0 -> 15351 bytes
.../apache/fop/render/pdf/pdfbox/ttsubset20.pdf | Bin 0 -> 19957 bytes
6 files changed, 69 insertions(+), 49 deletions(-)
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java b/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java
index b1e8946..60812c9 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleByteFont.java
@@ -234,8 +234,7 @@ public class FOPPDFSingleByteFont extends SingleByteFont implements FOPPDFFont {
int gid = entry.getValue();
GlyphData glyphData = ttfont.getGlyph().getGlyph(gid);
if (params.isRemapSingleByteFontEnabled() && gid != 0 && hasGlyph(glyphData) && !charMapGlobal.isEmpty()
- && tempCmap.glyphIdToCharacterCode.containsValue(gid)
- && !tempCmap.glyphIdToCharacterCode.containsKey(charCode)) {
+ && tempCmap.needsRemap(gid, charCode)) {
//Move glyphs to different gid when 2 fonts use same gid with different char code
if (oldToNewGIMapPerFont.containsKey(gid)) {
gid = oldToNewGIMapPerFont.get(gid);
@@ -246,9 +245,11 @@ public class FOPPDFSingleByteFont extends SingleByteFont implements FOPPDFFont {
|| hasGlyph(ttfont.getGlyph().getGlyph(newGid))) {
newGid++;
}
- oldToNewGIMap.put(gid, newGid);
- oldToNewGIMapPerFont.put(gid, newGid);
- gid = newGid;
+ if (newGid < ttfont.getNumberOfGlyphs()) {
+ oldToNewGIMap.put(gid, newGid);
+ oldToNewGIMapPerFont.put(gid, newGid);
+ gid = newGid;
+ }
}
}
if (gid != 0 && !tempCmap.glyphIdToCharacterCode.containsKey(charCode)
diff --git a/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java b/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java
index 95624bf..c2aa404 100644
--- a/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java
+++ b/src/java/org/apache/fop/render/pdf/pdfbox/MergeTTFonts.java
@@ -92,20 +92,20 @@ public class MergeTTFonts extends TTFSubSetFile implements MergeFonts {
(int)entry.getOffset() + glyphOffset,
glyphLength);
- Glyph g = new Glyph(glyphData, mtxTab[origGlyphIndex],
+ Glyph glyph = new Glyph(glyphData, mtxTab[origGlyphIndex],
composedGlyphs.contains(origGlyphIndex),
compositeGlyphs.contains(origGlyphIndex), origGlyphIndex);
if (!cid && (origIndexesLen == 0 || (glyphLength > 0 && i > 0))) {
if (added.containsKey(i)) {
Glyph existing = added.get(i);
- if (existing.data.length == 0) {
- added.put(i, g);
+ if (existing.data.length == 0 || existing.origGlyphIndex == 0) {
+ added.put(i, glyph);
}
} else {
- added.put(i, g);
+ added.put(i, glyph);
}
} else if (cid) {
- added.put(i + origIndexesLen, g);
+ added.put(i + origIndexesLen, glyph);
}
}
if (!cid) {
@@ -586,5 +586,10 @@ public class MergeTTFonts extends TTFSubSetFile implements MergeFonts {
}
return glyphIdToCharacterCode;
}
+
+ public boolean needsRemap(int gid, int charCode) {
+ return (glyphIdToCharacterCode.containsKey(charCode) && glyphIdToCharacterCode.get(charCode) != gid)
+ || (glyphIdToCharacterCode.containsValue(gid) && !glyphIdToCharacterCode.containsKey(charCode));
+ }
}
}
diff --git a/test/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleMultiByteFontTestCase.java b/test/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleMultiByteFontTestCase.java
index b00636c..c9b6b47 100644
--- a/test/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleMultiByteFontTestCase.java
+++ b/test/java/org/apache/fop/render/pdf/pdfbox/FOPPDFSingleMultiByteFontTestCase.java
@@ -72,6 +72,9 @@ import org.apache.fop.pdf.PDFMergeFontsParams;
public class FOPPDFSingleMultiByteFontTestCase {
private static final String TTSubset16 = "ttsubset16.pdf";
private static final String TTSubset17 = "ttsubset17.pdf";
+ private static final String TTSubset18 = "ttsubset18.pdf";
+ private static final String TTSubset19 = "ttsubset19.pdf";
+ private static final String TTSubset20 = "ttsubset20.pdf";
private PDFMergeFontsParams params = new PDFMergeFontsParams(true);
private COSDictionary getFont(PDDocument doc, String internalname) {
@@ -332,15 +335,12 @@ public class FOPPDFSingleMultiByteFontTestCase {
public void testNoEOFOnValidation() throws IOException {
PDDocument doc = PDFBoxAdapterTestCase.load(FontMergeTestCase.TTSubset1);
PDDocument doc2 = PDFBoxAdapterTestCase.load(FontMergeTestCase.TTSubset5);
-
PDFBoxEventProducer eventProducer = mock(PDFBoxEventProducer.class);
FOPPDFSingleByteFont sbFont = new FOPPDFSingleByteFont(getFont(doc, "R11"), "QOYQBZ+TimesNewRomanPSMT",
getEventBroadcaster(eventProducer), params);
sbFont.addFont(getFont(doc2, "F1"));
-
doc.close();
doc2.close();
-
sbFont.getInputStream();
verifyNoEvents(eventProducer);
}
@@ -365,45 +365,54 @@ public class FOPPDFSingleMultiByteFontTestCase {
@Test
public void testValidationSingleByteFont() throws IOException {
- validateSingleByteFont(FontMergeTestCase.TTSubset3, FontMergeTestCase.TTSubset5,
- "QOYQBZ+TimesNewRomanPSMT", "F1", true);
- validateSingleByteFont(FontMergeTestCase.TTSubset14, FontMergeTestCase.TTSubset15,
- "Montserrat-Regular", "TT1", true);
+ validateSingleByteFont("QOYQBZ+TimesNewRomanPSMT", "F1", true,
+ FontMergeTestCase.TTSubset3, FontMergeTestCase.TTSubset5);
+ validateSingleByteFont("Montserrat-Regular", "TT1", true,
+ FontMergeTestCase.TTSubset14, FontMergeTestCase.TTSubset15);
}
@Test
public void testTTSubsetRemapGid() throws IOException {
- InputStream is = validateSingleByteFont(TTSubset16, TTSubset17,
- "Montserrat-Regular", "TT0", true);
- TrueTypeFont mergedTTF = new TTFParser().parse(new RandomAccessReadBuffer(is));
+ TrueTypeFont mergedTTF = validateSingleByteFont("Montserrat-Regular", "TT0", true, TTSubset16, TTSubset17);
List<Integer> gids = new ArrayList<>();
for (int i = 0; i < mergedTTF.getNumberOfGlyphs(); i++) {
if (mergedTTF.getGlyph().getGlyph(i).getNumberOfContours() != 0) {
gids.add(i);
}
}
- Assert.assertEquals(124, gids.size());
- Assert.assertTrue(gids.contains(242));
+ Assert.assertEquals(165, gids.size());
+ for (int gid = 242; gid < 260; gid++) {
+ Assert.assertTrue(String.valueOf(gid), gids.contains(gid));
+ }
+ for (int gid = 270; gid < 294; gid++) {
+ Assert.assertTrue(String.valueOf(gid), gids.contains(gid));
+ }
Assert.assertEquals(3, mergedTTF.getGlyph().getGlyph(167).getNumberOfContours());
- compareGlyphsUsingTTSubset16And17(mergedTTF);
+ Assert.assertEquals(Arrays.asList(8211, 37, 74), compareGlyphs(mergedTTF, TTSubset16, TTSubset17));
}
- private void compareGlyphsUsingTTSubset16And17(TrueTypeFont mergedTTF) throws IOException {
- Map<Integer, GlyphData> glyphsFromInput1 = getGlyphs(TTSubset16, "TT0");
- Assert.assertEquals(74, glyphsFromInput1.size());
- for (Map.Entry<Integer, GlyphData> entry : glyphsFromInput1.entrySet()) {
- compareGlyph(mergedTTF, entry.getKey(), entry.getValue());
- }
- Map<Integer, GlyphData> glyphsFromInput2 = getGlyphs(TTSubset17, "TT0");
- Assert.assertEquals(54, glyphsFromInput2.size());
+ @Test
+ public void testTTSubsetRemapGid2() throws IOException {
+ TrueTypeFont mergedTTF = validateSingleByteFont("Montserrat", "TT0", true, TTSubset18, TTSubset19, TTSubset20);
+ Assert.assertEquals(1, mergedTTF.getGlyph().getGlyph(1608).getNumberOfContours());
+ Assert.assertEquals(Arrays.asList(8212, 55, 85), compareGlyphs(mergedTTF, TTSubset18, TTSubset19, TTSubset20));
+ }
+
+ private List<Integer> compareGlyphs(TrueTypeFont mergedTTF, String... files) throws IOException {
+ List<Integer> lastGlyphsChecked = new ArrayList<>();
List<Integer> glyphsChecked = new ArrayList<>();
- for (Map.Entry<Integer, GlyphData> entry : glyphsFromInput2.entrySet()) {
- if (!glyphsFromInput1.containsKey(entry.getKey())) {
- compareGlyph(mergedTTF, entry.getKey(), entry.getValue());
- glyphsChecked.add(entry.getKey());
+ for (String file : files) {
+ lastGlyphsChecked.clear();
+ Map<Integer, GlyphData> glyphsFromInput = getGlyphs(file, "TT0");
+ for (Map.Entry<Integer, GlyphData> entry : glyphsFromInput.entrySet()) {
+ if (!glyphsChecked.contains(entry.getKey())) {
+ compareGlyph(mergedTTF, entry.getKey(), entry.getValue());
+ glyphsChecked.add(entry.getKey());
+ lastGlyphsChecked.add(entry.getKey());
+ }
}
}
- Assert.assertEquals(Arrays.asList(8211, 37, 74), glyphsChecked);
+ return lastGlyphsChecked;
}
private void compareGlyph(TrueTypeFont mergedTTF, int charCode, GlyphData glyphFromInput) throws IOException {
@@ -432,9 +441,7 @@ public class FOPPDFSingleMultiByteFontTestCase {
@Test
public void testTTSubsetNoRemapGid() throws IOException {
- InputStream is = validateSingleByteFont(TTSubset16, TTSubset17,
- "Montserrat", "TT0", false);
- TrueTypeFont ttf = new TTFParser().parse(new RandomAccessReadBuffer(is));
+ TrueTypeFont ttf = validateSingleByteFont("Montserrat", "TT0", false, TTSubset16, TTSubset17);
List<Integer> gids = new ArrayList<>();
for (int i = 0; i < ttf.getNumberOfGlyphs(); i++) {
if (ttf.getGlyph().getGlyph(i).getNumberOfContours() != 0) {
@@ -445,16 +452,23 @@ public class FOPPDFSingleMultiByteFontTestCase {
Assert.assertFalse(gids.contains(242));
}
- private InputStream validateSingleByteFont(String firstFile, String secondFile, String fontName,
- String internalName, boolean remapFont) throws IOException {
- PDDocument doc = PDFBoxAdapterTestCase.load(firstFile);
- PDDocument doc2 = PDFBoxAdapterTestCase.load(secondFile);
- FOPPDFSingleByteFont sbFont = new FOPPDFSingleByteFont(getFont(doc, internalName), fontName,
- new DefaultEventBroadcaster(), new PDFMergeFontsParams(remapFont));
- sbFont.addFont(getFont(doc2, internalName));
- doc.close();
- doc2.close();
- return sbFont.getInputStream();
+ private TrueTypeFont validateSingleByteFont(String fontName, String internalName, boolean remap, String... files)
+ throws IOException {
+ FOPPDFSingleByteFont sbFont = null;
+ PDFBoxEventProducer eventProducer = mock(PDFBoxEventProducer.class);
+ for (String file : files) {
+ PDDocument doc = PDFBoxAdapterTestCase.load(file);
+ if (sbFont == null) {
+ sbFont = new FOPPDFSingleByteFont(getFont(doc, internalName), fontName,
+ getEventBroadcaster(eventProducer), new PDFMergeFontsParams(remap));
+ } else {
+ sbFont.addFont(getFont(doc, internalName));
+ }
+ doc.close();
+ }
+ InputStream is = sbFont.getInputStream();
+ verifyNoEvents(eventProducer);
+ return new TTFParser().parse(new RandomAccessReadBuffer(is));
}
private EventBroadcaster getEventBroadcaster(PDFBoxEventProducer eventProducer) {
diff --git a/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset18.pdf b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset18.pdf
new file mode 100755
index 0000000..d98ff71
Binary files /dev/null and b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset18.pdf differ
diff --git a/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset19.pdf b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset19.pdf
new file mode 100755
index 0000000..dcbb8e1
Binary files /dev/null and b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset19.pdf differ
diff --git a/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset20.pdf b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset20.pdf
new file mode 100755
index 0000000..0a49b55
Binary files /dev/null and b/test/resources/org/apache/fop/render/pdf/pdfbox/ttsubset20.pdf differ
---------------------------------------------------------------------
To unsubscribe, e-mail: commits-unsubscribe@xmlgraphics.apache.org
For additional commands, e-mail: commits-help@xmlgraphics.apache.org