Skip to content

Commit bf599ce

Browse files
ThomasTJdevbung87
andauthored
Implement option to embed fonts (#45)
* pass around 'embedFonts` and pre-cache charmap * fix wrong width with some fonts * font embedding * Remove demo/test_embedding_size.nim from version control * `drawTextAsPaths` if not embed * feat: implement font embedding modes and improve text selectability - Add FontRenderMode enum with frmDefault, frmEmbed, and frmPathRendering options - Implement full font embedding with proper Unicode mapping for text extraction - Fix ToUnicode CMap generation to use correct GID mapping based on render mode - Update font subsetting logic to handle different rendering modes - Improve character-to-glyph mapping for embedded vs subset fonts - Add renderMode parameter to font creation and management functions * add `frmDefault` example * add `demo/embed_fonts.pdf` --------- Co-authored-by: bung87 <crc32@qq.com>
1 parent eea8a36 commit bf599ce

File tree

10 files changed

+747
-121
lines changed

10 files changed

+747
-121
lines changed

demo/embed_fonts.nim

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
import streams, nimPDF, unittest
2+
3+
proc draw_title(doc: PDF, text: string) =
4+
let size = getSizeFromName("A4")
5+
6+
# Use Helvetica (Base14) for title to avoid affecting KaiTi embedding status
7+
doc.setFont("Helvetica", {FS_BOLD}, 12, ENC_STANDARD)
8+
let tw = doc.getTextWidth(text)
9+
let x = size.width.toMM / 2 - tw / 2
10+
11+
doc.setFillColor(0, 0, 0)
12+
doc.drawText(x, 10.0, text)
13+
doc.setStrokeColor(0, 0, 0)
14+
doc.drawRect(10, 15, size.width.toMM - 20, size.height.toMM - 25)
15+
doc.stroke()
16+
17+
proc createPDF(doc: PDF) =
18+
let size = getSizeFromName("A4")
19+
let SAMP_TEXT = "The Quick Brown Fox Jump Over The Lazy Dog"
20+
21+
doc.addPage(size, PGO_PORTRAIT)
22+
draw_title(doc, "FONT RENDERING MODES DEMO")
23+
24+
# Example 1: Font with renderMode=frmEmbed
25+
doc.setFillColor(0, 0, 0) # Set black color for text
26+
doc.setFont("Calligrapher", {FS_REGULAR}, 10, ENC_STANDARD, renderMode = frmEmbed)
27+
doc.drawText(15, 30, "Calligrapher - renderMode=frmEmbed")
28+
29+
# Example 2: Korean text with Eunjin font (embedded)
30+
doc.setFillColor(0, 0, 0) # Set black color for text
31+
doc.setFont("Eunjin", {FS_REGULAR}, 10, ENC_UTF8, renderMode = frmEmbed)
32+
doc.drawText(15, 60, "은진 - 한국어 테스트 (embedded)")
33+
34+
# Example 3: Path rendering (text drawn as vector paths)
35+
doc.setFillColor(0, 0, 0) # Set black color for text
36+
doc.setFont("KaiTi", {FS_REGULAR}, 10, enc = ENC_UTF8, renderMode = frmPathRendering)
37+
doc.drawText(15, 90, "你好世界 (text drawn as vector paths)")
38+
39+
# Example 4: Base14 font (embedding flag ignored)
40+
doc.setFillColor(0, 0, 0) # Set black color for text
41+
doc.setFont("Times", {FS_REGULAR}, 10, ENC_STANDARD, renderMode = frmEmbed)
42+
doc.drawText(15, 120, "Times (Base14 ignores flag)")
43+
44+
# Example 5: FreeMono with renderMode=frmDefault
45+
doc.setFillColor(0, 0, 0) # Set black color for text
46+
doc.setFont("FreeMono", {FS_REGULAR}, 10, ENC_UTF8, renderMode = frmDefault)
47+
doc.drawText(15, 150, "FreeMono - The Quick Brown Fox Jump Over The Lazy Dog")
48+
49+
50+
doc.setInfo(DI_TITLE, "Font Rendering Modes Demo")
51+
doc.setInfo(DI_AUTHOR, "Andri Lim")
52+
doc.setInfo(DI_SUBJECT, "Demonstrating three font rendering modes: frmDefault, frmEmbed, frmPathRendering")
53+
54+
proc main(): bool {.discardable.} =
55+
#echo currentSourcePath()
56+
var fileName = "embed_fonts.pdf"
57+
var file = newFileStream(fileName, fmWrite)
58+
59+
if file != nil:
60+
var opts = newPDFOptions()
61+
opts.addFontsPath("fonts")
62+
63+
echo "Creating PDF with font rendering modes demonstration..."
64+
echo "- frmDefault: No embedding, standard text rendering"
65+
echo "- frmEmbed: Text rendering with font embedding"
66+
echo "- frmPathRendering: Text drawn as vector paths (not selectable)"
67+
echo "- Check text copying/pasting to verify different behaviors"
68+
69+
var doc = newPDF(opts)
70+
doc.createPDF()
71+
doc.writePDF(file)
72+
file.close()
73+
echo "PDF created successfully: ", fileName
74+
echo "Try copying text from different lines to see embedding effects"
75+
return true
76+
77+
echo "cannot open: ", fileName
78+
result = false
79+
80+
main()

demo/embed_fonts.pdf

162 KB
Binary file not shown.

demo/test.nim

Lines changed: 14 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,4 @@
1-
import
2-
std/[streams, strutils],
3-
nimPDF,
4-
unittest
5-
1+
import streams, nimPDF, unittest, strutils
62
proc draw_title(doc: PDF, text:string) =
73
let size = getSizeFromName("A4")
84

@@ -46,48 +42,48 @@ proc test(doc: PDF) =
4642
var tw = doc.getTextWidth(text)
4743
var th = doc.getTextHeight(text)
4844
check:
49-
tw.formatFloat(ffDecimal, 2) == "11.39"
50-
th.formatFloat(ffDecimal, 2) == "3.59"
45+
$tw == "11.39"
46+
$th == "3.59"
5147

5248
test "getTextWidth and GetTextHeight TTF":
5349
doc.setFont("FreeMono", {FS_REGULAR}, 5)
5450
var tw = doc.getTextWidth(text)
5551
var th = doc.getTextHeight(text)
5652
check:
57-
tw.formatFloat(ffDecimal, 2) == "15.00"
58-
th.formatFloat(ffDecimal, 2) == "3.02"
53+
$tw.formatFloat(ffDecimal, 2) == "15.00"
54+
$th.formatFloat(ffDecimal, 2) == "3.02"
5955

6056
test "getVTextWidth and GetVTextHeight base14":
6157
doc.setFont("Helvetica", {FS_REGULAR}, 5)
6258
var tw = doc.getVTextWidth(text)
6359
var th = doc.getVTextHeight(text)
6460
check:
65-
tw.formatFloat(ffDecimal, 2) == "3.61"
66-
th.formatFloat(ffDecimal, 2) == "14.05"
61+
$tw.formatFloat(ffDecimal, 2) == "3.61"
62+
$th.formatFloat(ffDecimal, 2) == "14.05"
6763

6864
test "getTextWidth and GetTextHeight TTF":
6965
doc.setFont("FreeMono", {FS_REGULAR}, 5)
7066
var tw = doc.getVTextWidth(text)
7167
var th = doc.getVTextHeight(text)
7268
check:
73-
tw.formatFloat(ffDecimal, 2) == "3.00"
74-
th.formatFloat(ffDecimal, 3) == "13.325"
69+
$tw.formatFloat(ffDecimal, 2) == "3.00"
70+
$th.formatFloat(ffDecimal, 3) == "13.325"
7571

76-
proc main() =
72+
proc main(): bool {.discardable.} =
73+
#echo currentSourcePath()
7774
var fileName = "test.pdf"
7875
var file = newFileStream(fileName, fmWrite)
7976

8077
if file != nil:
81-
var opts = newPDFOptions()
82-
opts.addFontsPath("fonts")
83-
var doc = newPDF(opts)
78+
var doc = newPDF()
8479
doc.createPDF()
8580
doc.writePDF(file)
8681
doc.test()
8782
file.close()
8883
echo "OK"
89-
return
84+
return true
9085

9186
echo "cannot open: ", fileName
87+
result = false
9288

9389
main()

demo/test_all.nim

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ import
99
link_annot,
1010
pagelabels,
1111
test,
12-
text_annot
12+
text_annot,
13+
embed_fonts

0 commit comments

Comments
 (0)