-
Notifications
You must be signed in to change notification settings - Fork 26
/
cpdfembed.ml
130 lines (117 loc) · 4.63 KB
/
cpdfembed.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
(* Embed a font *)
open Pdfutil
type t = Pdftext.font list * (int, int * int) Hashtbl.t (* Table returns font number and charcode for given unicode codepoint *)
type cpdffont =
PreMadeFontPack of t
| EmbedInfo of {fontfile : Pdfio.bytes; fontname : string; encoding : Pdftext.encoding}
| ExistingNamedFont
let fontpack_of_standardfont sf =
let te = Pdftext.text_extractor_of_font_real sf in
let table = null_hash () in
for x = 0 to 255 do
let u = hd (Pdftext.codepoints_of_text te (string_of_char (char_of_int x))) in
Hashtbl.add table u (0, x)
done;
([sf], table)
let get_char (fonts, table) u =
match Hashtbl.find table u with
| (n, charcode) -> Some (charcode, n, List.nth fonts n)
| exception Not_found -> None
let fontnum = ref 0
let basename () =
incr fontnum;
"AAAAA" ^ string_of_char (char_of_int (!fontnum + 65))
let make_single_font ~fontname ~encoding pdf f =
let name_1 = basename () in
let module TT = Cpdftruetype in
let fontfile =
let len = Pdfio.bytes_size f.TT.subset_fontfile in
Pdf.Stream
{contents =
(Pdf.Dictionary
[("/Length", Pdf.Integer len); ("/Length1", Pdf.Integer len)],
Pdf.Got f.TT.subset_fontfile)}
in
let fontfile_num = Pdf.addobj pdf fontfile in
let open Pdftext in
let fontmetrics =
let a = Array.make 256 0. in
for x = f.TT.firstchar to f.TT.lastchar do
a.(x) <- float_of_int (f.TT.widths.(x - f.TT.firstchar))
done;
a
in
(f.TT.subset,
SimpleFont
{fonttype = Truetype;
basefont = Printf.sprintf "/%s+%s" name_1 fontname;
fontmetrics = Some fontmetrics;
firstchar = f.TT.firstchar;
lastchar = f.TT.lastchar;
widths = f.TT.widths;
fontdescriptor = Some
{ascent = float_of_int f.TT.ascent;
descent = float_of_int f.TT.descent;
avgwidth = float_of_int f.TT.avgwidth;
maxwidth = float_of_int f.TT.maxwidth;
flags = f.TT.flags;
italicangle = float_of_int f.TT.italicangle;
capheight = float_of_int f.TT.capheight;
xheight = float_of_int f.TT.xheight;
stemv = float_of_int f.TT.stemv;
fontbbox = (float_of_int f.TT.minx, float_of_int f.TT.miny,
float_of_int f.TT.maxx, float_of_int f.TT.maxy);
fontfile = Some (FontFile2 fontfile_num);
charset = None;
tounicode = f.TT.tounicode};
encoding})
let make_fontpack_hashtable fs =
let indexes = indx0 fs in
let table = null_hash () in
iter2
(fun i (subset, f) ->
let charcode_extractor = Pdftext.charcode_extractor_of_font_real f in
iter
(fun u ->
match charcode_extractor u with
| Some x -> Hashtbl.add table u (i, x)
| None -> Printf.printf "charcode_extractor could not find char in make_fontpack_hashtable\n")
subset)
indexes fs;
table
let embed_truetype pdf ~fontfile ~fontname ~codepoints ~encoding =
if codepoints = [] then ([], null_hash ()) else (* Can't call Cpdftruetype.parse with empty codepoint set. *)
let fs = Cpdftruetype.parse ~subset:codepoints fontfile encoding in
let subsets_and_their_fonts = map (make_single_font ~fontname ~encoding pdf) fs in
(map snd subsets_and_their_fonts, make_fontpack_hashtable subsets_and_their_fonts)
let rec collate_runs cfn a = function
| [] -> rev (map rev a)
| (charcode, fontnum, font) as h::t ->
match a with
| [] -> collate_runs fontnum [[h]] t
| this::rest ->
if fontnum = cfn
then collate_runs cfn ((h::this)::rest) t
else collate_runs fontnum ([h]::this::rest) t
let collate_runs = function
| [] -> []
| (_, fontnum, _)::_ as l -> collate_runs fontnum [] l
let fontnames =
[(Pdftext.TimesRoman, ["NimbusRoman-Regular.ttf"]);
(Pdftext.TimesBold, ["NimbusRoman-Bold.ttf"]);
(Pdftext.TimesItalic, ["NimbusRoman-Italic.ttf"]);
(Pdftext.TimesBoldItalic, ["NimbusRoman-BoldItalic.ttf"]);
(Pdftext.Helvetica, ["NimbusSans-Regular.ttf"]);
(Pdftext.HelveticaBold, ["NimbusSans-Bold.ttf"]);
(Pdftext.HelveticaOblique, ["NimbusSans-Italic.ttf"]);
(Pdftext.HelveticaBoldOblique, ["NimbusSans-BoldItalic.ttf"]);
(Pdftext.Courier, ["NimbusMonoPS-Regular.ttf"]);
(Pdftext.CourierBold, ["NimbusMonoPS-Bold.ttf"]);
(Pdftext.CourierOblique, ["NimbusMonoPS-Italic.ttf"]);
(Pdftext.CourierBoldOblique, ["NimbusMonoPS-BoldItalic.ttf"]);
(Pdftext.Symbol, ["StandardSymbolsPS.ttf"]);
(Pdftext.ZapfDingbats, ["D050000L.ttf"])]
let load_substitute dirname f =
let filename = hd (List.assoc f fontnames) in
(Pdfio.bytes_of_string (contents_of_file (Filename.concat dirname filename)),
Filename.remove_extension filename)