Skip to content

Commit 032b32d

Browse files
committed
Fix #773
1 parent 055e03f commit 032b32d

File tree

15 files changed

+278
-93
lines changed

15 files changed

+278
-93
lines changed

pkg/api/test/createFromJSON_test.go

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -163,7 +163,6 @@ func TestCreateSinglePageDemoFormsViaJson(t *testing.T) {
163163
inFileJSON string
164164
outFile string
165165
}{
166-
167166
{"TestFormDemoEN", "english.json", "english.pdf"}, // Core font (Helvetica)
168167
{"TestFormDemoUK", "ukrainian.json", "ukrainian.pdf"}, // User font (Roboto-Regular)
169168
{"TestFormDemoAR", "arabic.json", "arabic.pdf"}, // User font RTL (Roboto-Regular)
@@ -203,7 +202,6 @@ func TestCreateDemoFormsViaJson(t *testing.T) {
203202
{"TestFormDemoIC", "icelandic.json", "icelandic.pdf"},
204203
{"TestFormDemoIT", "italian.json", "italian.pdf"},
205204
{"TestFormDemoNO", "norwegian.json", "norwegian.pdf"},
206-
{"TestFormDemoPO", "polish.json", "polish.pdf"},
207205
{"TestFormDemoPT", "portuguese.json", "portuguese.pdf"},
208206
{"TestFormDemoSK", "slovak.json", "slovak.pdf"},
209207
{"TestFormDemoSL", "slovenian.json", "slovenian.pdf"},
@@ -218,6 +216,7 @@ func TestCreateDemoFormsViaJson(t *testing.T) {
218216
{"TestFormDemoCZ", "czech.json", "czech.pdf"},
219217
{"TestFormDemoGR", "greek.json", "greek.pdf"},
220218
{"TestFormDemoKU", "kurdish.json", "kurdish.pdf"},
219+
{"TestFormDemoPO", "polish.json", "polish.pdf"},
221220
{"TestFormDemoRO", "romanian.json", "romanian.pdf"},
222221
{"TestFormDemoRU", "russian.json", "russian.pdf"},
223222
{"TestFormDemoTK", "turkish.json", "turkish.pdf"},

pkg/font/install.go

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -663,7 +663,10 @@ func installTrueTypeRep(fontDir, fontName string, header []byte, tables map[stri
663663
}
664664
fd.FontFile = bb
665665

666-
log.CLI.Println(fd.PostscriptName)
666+
if log.CLIEnabled() {
667+
log.CLI.Println(fd.PostscriptName)
668+
}
669+
667670
gobName := filepath.Join(fontDir, fd.PostscriptName+".gob")
668671

669672
// Write the populated ttf struct as gob.
@@ -747,6 +750,16 @@ func InstallTrueTypeFont(fontDir, fontName string) error {
747750
return installTrueTypeRep(fontDir, fontName, header, tables)
748751
}
749752

753+
// InstallFontFromBytes saves an internal representation of TrueType font fontName to the pdfcpu config dir.
754+
func InstallFontFromBytes(fontDir, fontName string, bb []byte) error {
755+
rd := bytes.NewReader(bb)
756+
header, tables, err := headerAndTables(fontName, rd, 0)
757+
if err != nil {
758+
return err
759+
}
760+
return installTrueTypeRep(fontDir, fontName, header, tables)
761+
}
762+
750763
func ttfTables(tableCount int, bb []byte) (map[string]*table, error) {
751764
tables := map[string]*table{}
752765
b := bb[12:]

pkg/font/metrics.go

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -347,6 +347,13 @@ func Size(text, fontName string, width float64) int {
347347
return fontScalingFactor(float64(w), width)
348348
}
349349

350+
// SizeForLineHeight returns the needed font size in points
351+
// for rendering using a given font name fitting into given line height lh.
352+
func SizeForLineHeight(fontName string, lh float64) int {
353+
fbb := BoundingBox(fontName)
354+
return int(math.Round(lh / (fbb.Height() / 1000)))
355+
}
356+
350357
// UserSpaceFontBBox returns the font box for given font name and font size in user space coordinates.
351358
func UserSpaceFontBBox(fontName string, fontSize int) *types.Rectangle {
352359
fontBBox := BoundingBox(fontName)

pkg/pdfcpu/font/fontDict.go

Lines changed: 75 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -51,8 +51,10 @@ var cjkParms = map[string]cjk{
5151
"KANA": {"UniJIS-UTF16-H", "Japan1", 7},
5252
"JPAN": {"UniJIS-UTF16-H", "Japan1", 7},
5353
// K
54-
"HANG": {"UniKS-UTF16-H", "KR", 9},
55-
"KORE": {"UniKS-UTF16-H", "KR", 9},
54+
"HANG": {"UniKS-UTF16-H", "Korea1", 1},
55+
"KORE": {"UniKS-UTF16-H", "Korea1", 1},
56+
//"HANG": {"UniKS-UTF16-H", "KR", 9},
57+
//"KORE": {"UniKS-UTF16-H", "KR", 9},
5658
}
5759

5860
func SupportedScript(s string) bool {
@@ -172,6 +174,56 @@ func ttfSubFontFile(xRefTable *model.XRefTable, ttf font.TTFLight, fontName stri
172174
return indRef, nil
173175
}
174176

177+
func PDFDocEncoding(xRefTable *model.XRefTable) (*types.IndirectRef, error) {
178+
arr := types.Array{
179+
types.Integer(24),
180+
types.Name("breve"), types.Name("caron"), types.Name("circumflex"), types.Name("dotaccent"),
181+
types.Name("hungarumlaut"), types.Name("ogonek"), types.Name("ring"), types.Name("tilde"),
182+
types.Integer(39),
183+
types.Name("quotesingle"),
184+
types.Integer(96),
185+
types.Name("grave"),
186+
types.Integer(128),
187+
types.Name("bullet"), types.Name("dagger"), types.Name("daggerdbl"), types.Name("ellipsis"), types.Name("emdash"), types.Name("endash"),
188+
types.Name("florin"), types.Name("fraction"), types.Name("guilsinglleft"), types.Name("guilsinglright"), types.Name("minus"), types.Name("perthousand"),
189+
types.Name("quotedblbase"), types.Name("quotedblleft"), types.Name("quotedblright"), types.Name("quoteleft"), types.Name("quoteright"), types.Name("quotesinglbase"),
190+
types.Name("trademark"), types.Name("fi"), types.Name("fl"), types.Name("Lslash"), types.Name("OE"), types.Name("Scaron"), types.Name("Ydieresis"),
191+
types.Name("Zcaron"), types.Name("dotlessi"), types.Name("lslash"), types.Name("oe"), types.Name("scaron"), types.Name("zcaron"),
192+
types.Integer(160),
193+
types.Name("Euro"),
194+
types.Integer(164),
195+
types.Name("currency"),
196+
types.Integer(166),
197+
types.Name("brokenbar"), types.Integer(168), types.Name("dieresis"), types.Name("copyright"), types.Name("ordfeminine"),
198+
types.Integer(172),
199+
types.Name("logicalnot"), types.Name(".notdef"), types.Name("registered"), types.Name("macron"), types.Name("degree"),
200+
types.Name("plusminus"), types.Name("twosuperior"), types.Name("threesuperior"), types.Name("acute"), types.Name("mu"),
201+
types.Integer(183),
202+
types.Name("periodcentered"), types.Name("cedilla"), types.Name("onesuperior"), types.Name("ordmasculine"),
203+
types.Integer(188),
204+
types.Name("onequarter"), types.Name("onehalf"), types.Name("threequarters"),
205+
types.Integer(192),
206+
types.Name("Agrave"), types.Name("Aacute"), types.Name("Acircumflex"), types.Name("Atilde"), types.Name("Adieresis"), types.Name("Aring"), types.Name("AE"),
207+
types.Name("Ccedilla"), types.Name("Egrave"), types.Name("Eacute"), types.Name("Ecircumflex"), types.Name("Edieresis"), types.Name("Igrave"), types.Name("Iacute"),
208+
types.Name("Icircumflex"), types.Name("Idieresis"), types.Name("Eth"), types.Name("Ntilde"), types.Name("Ograve"), types.Name("Oacute"), types.Name("Ocircumflex"),
209+
types.Name("Otilde"), types.Name("Odieresis"), types.Name("multiply"), types.Name("Oslash"), types.Name("Ugrave"), types.Name("Uacute"), types.Name("Ucircumflex"),
210+
types.Name("Udieresis"), types.Name("Yacute"), types.Name("Thorn"), types.Name("germandbls"), types.Name("agrave"), types.Name("aacute"), types.Name("acircumflex"),
211+
types.Name("atilde"), types.Name("adieresis"), types.Name("aring"), types.Name("ae"), types.Name("ccedilla"), types.Name("egrave"), types.Name("eacute"), types.Name("ecircumflex"),
212+
types.Name("edieresis"), types.Name("igrave"), types.Name("iacute"), types.Name("icircumflex"), types.Name("idieresis"), types.Name("eth"), types.Name("ntilde"),
213+
types.Name("ograve"), types.Name("oacute"), types.Name("ocircumflex"), types.Name("otilde"), types.Name("odieresis"), types.Name("divide"), types.Name("oslash"),
214+
types.Name("ugrave"), types.Name("uacute"), types.Name("ucircumflex"), types.Name("udieresis"), types.Name("yacute"), types.Name("thorn"), types.Name("ydieresis"),
215+
}
216+
217+
d := types.Dict(
218+
map[string]types.Object{
219+
"Type": types.Name("Encoding"),
220+
"Differences": arr,
221+
},
222+
)
223+
224+
return xRefTable.IndRefForNewObject(d)
225+
}
226+
175227
func coreFontDict(xRefTable *model.XRefTable, coreFontName string) (*types.IndirectRef, error) {
176228
d := types.NewDict()
177229
d.InsertName("Type", "Font")
@@ -180,6 +232,15 @@ func coreFontDict(xRefTable *model.XRefTable, coreFontName string) (*types.Indir
180232
if coreFontName != "Symbol" && coreFontName != "ZapfDingbats" {
181233
d.InsertName("Encoding", "WinAnsiEncoding")
182234
}
235+
// if coreFontName == "Helvetica" {
236+
// indRef, err := PDFDocEncoding(xRefTable)
237+
// if err != nil {
238+
// return nil, err
239+
// }
240+
// d.Insert("Encoding", *indRef)
241+
// } else if coreFontName != "Symbol" && coreFontName != "ZapfDingbats" {
242+
// d.InsertName("Encoding", "WinAnsiEncoding")
243+
// }
183244
return xRefTable.IndRefForNewObject(d)
184245
}
185246

@@ -734,8 +795,8 @@ func subFontPrefix() string {
734795
return string(bb)
735796
}
736797

737-
// CIDFontSpecialEncDict returns the descendant font dict with special encoding for Type0 fonts.
738-
func CIDFontSpecialEncDict(xRefTable *model.XRefTable, ttf font.TTFLight, fontName, baseFontName, lang string, parms *cjk) (*types.IndirectRef, error) {
798+
// CIDFontDict returns the descendant font dict with special encoding for Type0 fonts.
799+
func CIDFontDict(xRefTable *model.XRefTable, ttf font.TTFLight, fontName, baseFontName, lang string, parms *cjk) (*types.IndirectRef, error) {
739800
fdIndRef, err := CIDFontDescriptor(xRefTable, ttf, fontName, baseFontName, lang, parms == nil)
740801
if err != nil {
741802
return nil, err
@@ -798,12 +859,14 @@ func CIDFontSpecialEncDict(xRefTable *model.XRefTable, ttf font.TTFLight, fontNa
798859
d["CIDToGIDMap"] = types.Name("Identity")
799860
}
800861

801-
wIndRef, err := CIDWidths(xRefTable, ttf, fontName, parms == nil, nil)
802-
if err != nil {
803-
return nil, err
804-
}
805-
if wIndRef != nil {
806-
d["W"] = *wIndRef
862+
if parms == nil {
863+
wIndRef, err := CIDWidths(xRefTable, ttf, fontName, parms == nil, nil)
864+
if err != nil {
865+
return nil, err
866+
}
867+
if wIndRef != nil {
868+
d["W"] = *wIndRef
869+
}
807870
}
808871

809872
return xRefTable.IndRefForNewObject(d)
@@ -841,7 +904,7 @@ func type0FontDict(xRefTable *model.XRefTable, fontName, lang, script string, in
841904
encoding = parms.encoding
842905
}
843906

844-
descendentFontIndRef, err := CIDFontSpecialEncDict(xRefTable, ttf, fontName, baseFontName, lang, parms)
907+
descendentFontIndRef, err := CIDFontDict(xRefTable, ttf, fontName, baseFontName, lang, parms)
845908
if err != nil {
846909
return nil, err
847910
}
@@ -850,7 +913,7 @@ func type0FontDict(xRefTable *model.XRefTable, fontName, lang, script string, in
850913
d.InsertName("Type", "Font")
851914
d.InsertName("Subtype", "Type0")
852915
d.InsertName("BaseFont", baseFontName)
853-
//d.InsertName("Name", fontName)
916+
d.InsertName("Name", fontName)
854917
d.InsertName("Encoding", encoding)
855918
d.Insert("DescendantFonts", types.Array{*descendentFontIndRef})
856919

pkg/pdfcpu/form/fill.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1096,6 +1096,7 @@ func FillForm(
10961096
if len(ctx.UsedGIDs[fName]) == 0 {
10971097
continue
10981098
}
1099+
// Update user font.
10991100
fDict, err := xRefTable.DereferenceDict(indRef)
11001101
if err != nil {
11011102
return false, nil, err
@@ -1119,7 +1120,7 @@ func FillForm(
11191120

11201121
// pdfcpu provides all appearance streams for form fields.
11211122
// Yet for some files and viewers form fields don't get rendered.
1122-
// In these cases you can order the viewer to provide form field appearance streams.
1123+
// In these cases you can force the viewer to provide form field appearance streams.
11231124
if ctx.NeedAppearances {
11241125
xRefTable.Form["NeedAppearances"] = types.Boolean(true)
11251126
}

pkg/pdfcpu/model/configuration.go

Lines changed: 24 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ import (
2424
"time"
2525

2626
"github.com/pdfcpu/pdfcpu/pkg/font"
27+
"github.com/pdfcpu/pdfcpu/pkg/log"
2728
"github.com/pdfcpu/pdfcpu/pkg/pdfcpu/types"
2829
)
2930

@@ -248,9 +249,12 @@ var ConfigPath string = "default"
248249

249250
var loadedDefaultConfig *Configuration
250251

251-
//go:embed config.yml
252+
//go:embed resources/config.yml
252253
var configFileBytes []byte
253254

255+
//go:embed resources/Roboto-Regular.ttf
256+
var robotoFontFileBytes []byte
257+
254258
func ensureConfigFileAt(path string) error {
255259
f, err := os.Open(path)
256260
if err != nil {
@@ -282,6 +286,25 @@ func EnsureDefaultConfigAt(path string) error {
282286
return err
283287
}
284288
//fmt.Println(loadedDefaultConfig)
289+
290+
files, err := os.ReadDir(font.UserFontDir)
291+
if err != nil {
292+
return err
293+
}
294+
295+
if len(files) == 0 {
296+
// Ensure Roboto font for form filling.
297+
fn := "Roboto-Regular"
298+
if log.CLIEnabled() {
299+
log.CLI.Printf("installing user font:")
300+
}
301+
if err := font.InstallFontFromBytes(font.UserFontDir, fn, robotoFontFileBytes); err != nil {
302+
if log.CLIEnabled() {
303+
log.CLI.Printf("%v", err)
304+
}
305+
}
306+
}
307+
285308
return font.LoadUserFonts()
286309
}
287310

167 KB
Binary file not shown.

pkg/pdfcpu/primitives/comboBox.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -792,7 +792,7 @@ func refreshComboBoxAP(ctx *model.Context, d types.Dict, v string, fonts map[str
792792
return err
793793
}
794794

795-
return UpdateForm(ctx.XRefTable, bb, irN)
795+
return updateForm(ctx.XRefTable, bb, irN)
796796
}
797797

798798
func EnsureComboBoxAP(ctx *model.Context, d types.Dict, v string, fonts map[string]types.IndirectRef) error {

pkg/pdfcpu/primitives/dateField.go

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,10 @@ func (df *DateField) renderN(xRefTable *model.XRefTable) ([]byte, error) {
449449
}
450450

451451
f := df.Font
452-
//cjk := fo.CJK(f.Script, f.Lang)
452+
if float64(f.Size) > h {
453+
f.Size = font.SizeForLineHeight(f.Name, h)
454+
}
455+
453456
lineBB := model.CalcBoundingBox(v, 0, 0, f.Name, f.Size)
454457
s := model.PrepBytes(xRefTable, v, f.Name, true, false)
455458
x := 2 * boWidth
@@ -929,7 +932,7 @@ func refreshDateFieldAP(ctx *model.Context, d types.Dict, v string, fonts map[st
929932
return err
930933
}
931934

932-
return UpdateForm(ctx.XRefTable, bb, irN)
935+
return updateForm(ctx.XRefTable, bb, irN)
933936
}
934937

935938
func EnsureDateFieldAP(ctx *model.Context, d types.Dict, v string, fonts map[string]types.IndirectRef) error {

0 commit comments

Comments
 (0)