Skip to content

Commit 8fcf80d

Browse files
yulian-gaponenkoiText-CI
authored andcommitted
Add CFF CIDFont support
In this case CIDs are not equal to GIDs in font processing. DEVSIX-5767 Autoported commit. Original commit hash: [4741f6509]
1 parent 5cc5795 commit 8fcf80d

34 files changed

+655
-42
lines changed
Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
/*
2+
This file is part of the iText (R) project.
3+
Copyright (c) 1998-2022 iText Group NV
4+
Authors: iText Software.
5+
6+
This program is offered under a commercial and under the AGPL license.
7+
For commercial licensing, contact us at https://itextpdf.com/sales. For AGPL licensing, see below.
8+
9+
AGPL licensing:
10+
This program is free software: you can redistribute it and/or modify
11+
it under the terms of the GNU Affero General Public License as published by
12+
the Free Software Foundation, either version 3 of the License, or
13+
(at your option) any later version.
14+
15+
This program is distributed in the hope that it will be useful,
16+
but WITHOUT ANY WARRANTY; without even the implied warranty of
17+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18+
GNU Affero General Public License for more details.
19+
20+
You should have received a copy of the GNU Affero General Public License
21+
along with this program. If not, see <https://www.gnu.org/licenses/>.
22+
*/
23+
using System;
24+
using System.Collections.Generic;
25+
using System.IO;
26+
using iText.Commons.Utils;
27+
using iText.IO.Source;
28+
using iText.Test;
29+
30+
namespace iText.IO.Font {
31+
public class CFFFontSubsetIntegrationTest : ExtendedITextTest {
32+
private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
33+
.CurrentContext.TestDirectory) + "/resources/itext/io/font/CFFFontSubsetIntegrationTest/";
34+
35+
private static readonly String FONTS_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
36+
.CurrentContext.TestDirectory) + "/resources/itext/io/font/sharedFontsResourceFiles/";
37+
38+
private static readonly String CJK_JP_BOLD_PATH = FONTS_FOLDER + "NotoSansCJKjp-Bold.otf";
39+
40+
private const int CJK_JP_BOLD_CFF_OFFSET = 259880;
41+
42+
private const int CJK_JP_BOLD_CFF_LENGTH = 16023217;
43+
44+
private static readonly String JP_REGULAR_PATH = FONTS_FOLDER + "NotoSansJP-Regular_charsetDataFormat0.otf";
45+
46+
private const int JP_REGULAR_CFF_OFFSET = 337316;
47+
48+
private const int JP_REGULAR_CFF_LENGTH = 4210891;
49+
50+
[NUnit.Framework.Test]
51+
public virtual void SubsetNotoSansCjkJpBoldNoUsedGlyphsTest() {
52+
String cmpCff = SOURCE_FOLDER + "subsetNotoSansCJKjpBoldNoUsedGlyphs.cff";
53+
ICollection<int> glyphsUsed = JavaCollectionsUtil.EmptySet<int>();
54+
byte[] cffSubsetBytes = SubsetNotoSansCjkJpBoldCff(CJK_JP_BOLD_PATH, CJK_JP_BOLD_CFF_OFFSET, CJK_JP_BOLD_CFF_LENGTH
55+
, glyphsUsed);
56+
int expectedSubsetLength = 279337;
57+
NUnit.Framework.Assert.AreEqual(expectedSubsetLength, cffSubsetBytes.Length);
58+
byte[] cmpBytes = File.ReadAllBytes(System.IO.Path.Combine(cmpCff));
59+
NUnit.Framework.Assert.AreEqual(cmpBytes, cffSubsetBytes);
60+
}
61+
62+
[NUnit.Framework.Test]
63+
public virtual void SubsetNotoSansCjkJpBoldTwoUsedGlyphsTest() {
64+
String cmpCff = SOURCE_FOLDER + "subsetNotoSansCJKjpBoldTwoUsedGlyphs.cff";
65+
// In this case cid == gid for given characters.
66+
// \u20eab "𠺫"
67+
int glyphCid1 = 59715;
68+
// \uff14 "4"
69+
int glyphCid2 = 59066;
70+
HashSet<int> glyphsUsed = new HashSet<int>(JavaUtil.ArraysAsList(glyphCid1, glyphCid2));
71+
byte[] cffSubsetBytes = SubsetNotoSansCjkJpBoldCff(CJK_JP_BOLD_PATH, CJK_JP_BOLD_CFF_OFFSET, CJK_JP_BOLD_CFF_LENGTH
72+
, glyphsUsed);
73+
int expectedSubsetLength = 365381;
74+
NUnit.Framework.Assert.AreEqual(expectedSubsetLength, cffSubsetBytes.Length);
75+
byte[] cmpBytes = File.ReadAllBytes(System.IO.Path.Combine(cmpCff));
76+
NUnit.Framework.Assert.AreEqual(cmpBytes, cffSubsetBytes);
77+
}
78+
79+
[NUnit.Framework.Test]
80+
public virtual void SubsetNotoSansJpRegularOneUsedGlyphTest() {
81+
// In this case cid != gid for given characters.
82+
// \u4FE1 "信"; gid: 0x0a72 / 2674
83+
int glyphGid1 = 2674;
84+
HashSet<int> glyphsUsed = new HashSet<int>(JavaCollectionsUtil.SingletonList(glyphGid1));
85+
byte[] cffSubsetBytes = SubsetNotoSansCjkJpBoldCff(JP_REGULAR_PATH, JP_REGULAR_CFF_OFFSET, JP_REGULAR_CFF_LENGTH
86+
, glyphsUsed);
87+
int expectedSubsetLength = 121796;
88+
NUnit.Framework.Assert.AreEqual(expectedSubsetLength, cffSubsetBytes.Length);
89+
byte[] cmpBytes = File.ReadAllBytes(System.IO.Path.Combine(SOURCE_FOLDER + "subsetNotoSansJPRegularOneUsedGlyph.cff"
90+
));
91+
NUnit.Framework.Assert.AreEqual(cmpBytes, cffSubsetBytes);
92+
}
93+
94+
private byte[] SubsetNotoSansCjkJpBoldCff(String otfFile, int offsetToCff, int cffLength, ICollection<int>
95+
glyphsUsed) {
96+
RandomAccessFileOrArray fontRaf = null;
97+
try {
98+
fontRaf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateBestSource(otfFile));
99+
byte[] cff = new byte[cffLength];
100+
try {
101+
fontRaf.Seek(offsetToCff);
102+
fontRaf.ReadFully(cff);
103+
}
104+
finally {
105+
fontRaf.Close();
106+
}
107+
CFFFontSubset cffFontSubset = new CFFFontSubset(cff, glyphsUsed);
108+
return cffFontSubset.Process();
109+
}
110+
finally {
111+
if (fontRaf != null) {
112+
fontRaf.Close();
113+
}
114+
}
115+
}
116+
}
117+
}

itext.tests/itext.io.tests/itext/io/font/CFFFontTest.cs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,17 @@ You should have received a copy of the GNU Affero General Public License
2727
namespace iText.IO.Font {
2828
public class CFFFontTest : ExtendedITextTest {
2929
private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
30-
.CurrentContext.TestDirectory) + "/resources/itext/io/font/otf/CFFFontTest/";
30+
.CurrentContext.TestDirectory) + "/resources/itext/io/font/sharedFontsResourceFiles/";
3131

3232
[NUnit.Framework.Test]
3333
public virtual void SeekTest() {
3434
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateBestSource
3535
(SOURCE_FOLDER + "NotoSansCJKjp-Bold.otf"));
36-
byte[] cff = new byte[16014190];
36+
int offsetToCff = 259880;
37+
int cffLength = 16023217;
38+
byte[] cff = new byte[cffLength];
3739
try {
38-
raf.Seek(283192);
40+
raf.Seek(offsetToCff);
3941
raf.ReadFully(cff);
4042
}
4143
finally {
@@ -57,9 +59,11 @@ public virtual void SeekTest() {
5759
public virtual void GetPositionTest() {
5860
RandomAccessFileOrArray raf = new RandomAccessFileOrArray(new RandomAccessSourceFactory().CreateBestSource
5961
(SOURCE_FOLDER + "NotoSansCJKjp-Bold.otf"));
60-
byte[] cff = new byte[16014190];
62+
int offsetToCff = 259880;
63+
int cffLength = 16023217;
64+
byte[] cff = new byte[cffLength];
6165
try {
62-
raf.Seek(283192);
66+
raf.Seek(offsetToCff);
6367
raf.ReadFully(cff);
6468
}
6569
finally {

itext.tests/itext.io.tests/itext/io/font/TrueTypeFontTest.cs

Lines changed: 43 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -21,24 +21,62 @@ You should have received a copy of the GNU Affero General Public License
2121
along with this program. If not, see <https://www.gnu.org/licenses/>.
2222
*/
2323
using System;
24+
using System.Collections.Generic;
25+
using iText.Commons.Utils;
2426
using iText.IO.Font.Otf;
2527
using iText.Test;
2628

2729
namespace iText.IO.Font {
2830
public class TrueTypeFontTest : ExtendedITextTest {
29-
private static readonly String sourceFolder = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
30-
.CurrentContext.TestDirectory) + "/resources/itext/io/font/TrueTypeFontTest/";
31+
private static readonly String SOURCE_FOLDER = iText.Test.TestUtil.GetParentProjectDirectory(NUnit.Framework.TestContext
32+
.CurrentContext.TestDirectory) + "/resources/itext/io/font/sharedFontsResourceFiles/";
3133

3234
[NUnit.Framework.Test]
3335
public virtual void NotoSansJpCmapTest() {
3436
// 信
3537
char jpChar = '\u4FE1';
36-
FontProgram fontProgram = FontProgramFactory.CreateFont(sourceFolder + "NotoSansJP-Regular.otf");
38+
FontProgram fontProgram = FontProgramFactory.CreateFont(SOURCE_FOLDER + "NotoSansJP-Regular_charsetDataFormat0.otf"
39+
);
3740
Glyph glyph = fontProgram.GetGlyph(jpChar);
3841
NUnit.Framework.Assert.AreEqual(new char[] { jpChar }, glyph.GetUnicodeChars());
3942
NUnit.Framework.Assert.AreEqual(20449, glyph.GetUnicode());
40-
// TODO DEVSIX-5767 actual expected value is 0x27d3
41-
NUnit.Framework.Assert.AreEqual(0x0a72, glyph.GetCode());
43+
NUnit.Framework.Assert.AreEqual(10195, glyph.GetCode());
44+
}
45+
46+
[NUnit.Framework.Test]
47+
public virtual void NotoSansScCmapTest() {
48+
// 易
49+
char chChar = '\u6613';
50+
FontProgram fontProgram = FontProgramFactory.CreateFont(SOURCE_FOLDER + "NotoSansSC-Regular.otf");
51+
Glyph glyph = fontProgram.GetGlyph(chChar);
52+
NUnit.Framework.Assert.AreEqual(new char[] { chChar }, glyph.GetUnicodeChars());
53+
NUnit.Framework.Assert.AreEqual(26131, glyph.GetUnicode());
54+
NUnit.Framework.Assert.AreEqual(20292, glyph.GetCode());
55+
}
56+
57+
[NUnit.Framework.Test]
58+
public virtual void NotoSansTcCmapTest() {
59+
// 易
60+
char chChar = '\u6613';
61+
FontProgram fontProgram = FontProgramFactory.CreateFont(SOURCE_FOLDER + "NotoSansTC-Regular.otf");
62+
Glyph glyph = fontProgram.GetGlyph(chChar);
63+
NUnit.Framework.Assert.AreEqual(new char[] { chChar }, glyph.GetUnicodeChars());
64+
NUnit.Framework.Assert.AreEqual(26131, glyph.GetUnicode());
65+
NUnit.Framework.Assert.AreEqual(20292, glyph.GetCode());
66+
}
67+
68+
[NUnit.Framework.Test]
69+
public virtual void NotoSansScMapGlyphsCidsToGidsTest() {
70+
// 易
71+
char chChar = '\u6613';
72+
int charCidInFont = 20292;
73+
int charGidInFont = 14890;
74+
TrueTypeFont trueTypeFontProgram = (TrueTypeFont)FontProgramFactory.CreateFont(SOURCE_FOLDER + "NotoSansSC-Regular.otf"
75+
);
76+
HashSet<int> glyphs = new HashSet<int>(JavaCollectionsUtil.SingletonList(charCidInFont));
77+
ICollection<int> actualResult = trueTypeFontProgram.MapGlyphsCidsToGids(glyphs);
78+
NUnit.Framework.Assert.AreEqual(1, actualResult.Count);
79+
NUnit.Framework.Assert.IsTrue(actualResult.Contains(charGidInFont));
4280
}
4381
}
4482
}

itext.tests/itext.io.tests/resources/itext/io/font/TrueTypeFontTest/NOTICE.txt

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

itext.tests/itext.io.tests/resources/itext/io/font/otf/CFFFontTest/NOTICE.txt

Lines changed: 0 additions & 5 deletions
This file was deleted.
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
This software uses the following test resources under the following licenses:
2+
| NotoSansJP-Regular_charsetDataFormat0.otf | OFL-1.1 | OFL.txt | Downloaded from https://fonts.google.com/noto/specimen/Noto+Sans+JP on 23.03.2022
3+
| NotoSansTC-Regular.otf | OFL-1.1 | OFL.txt | Based on commit 165c01b46ea533872e002e0785ff17e44f6d97d8 (30.04.2021) from repository: "https://github.com/googlefonts/noto-cjk"
4+
| NotoSansSC-Regular.otf | OFL-1.1 | OFL.txt | Based on commit 165c01b46ea533872e002e0785ff17e44f6d97d8 (30.04.2021) from repository: "https://github.com/googlefonts/noto-cjk"
5+
| NotoSansCJKjp-Bold.otf | OFL-1.1 | OFL.txt | Based on commit 165c01b46ea533872e002e0785ff17e44f6d97d8 (30.04.2021) from repository: "https://github.com/googlefonts/noto-cjk"

0 commit comments

Comments
 (0)