forked from johnwhitington/camlpdf
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpdftruetype.ml
636 lines (588 loc) · 27.9 KB
/
pdftruetype.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
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
(* Convert a TrueType Font to a Type 3 font. *)
open Pdfutil
open Pdfio
let dbg = ref false (* text-based debug *)
let dbgg = ref false (* graphical debug *)
(* 32-bit signed fixed-point number (16.16) returned as two ints *)
let read_fixed b =
let a = getval_31 b 16 in
let b = getval_31 b 16 in
a, b
(* 16-bit unsigned integer *)
let read_ushort b = getval_31 b 16
(* 32-bit unsigned integer *)
let read_ulong b = getval_32 b 32
(* Signed byte *)
let read_byte b = getval_31 b 8
(* Signed short *)
let read_short b = sign_extend 16 (getval_31 b 16)
(* fword *)
let read_fword = read_short
(* f2dot14 - 2 bit signed integer part, 14 bit unsigned fraction *)
let read_f2dot14 b =
let v = read_ushort b in
float_of_int (sign_extend 2 (v lsr 14)) +. (float_of_int (v land 0x3FFF) /. 16384.)
(* discard n bytes *)
let discard_bytes b n =
for x = 1 to n do ignore (getval_31 b 8) done
(* longDateTime (stub) *)
let read_longdatetime b = discard_bytes b 8; 0
(* The empty glyph. *)
let notdef =
{Pdfgraphics.elements = [];
Pdfgraphics.fonts = [];
Pdfgraphics.resources = Pdf.Dictionary []}
let string_of_tag t =
let a = i32toi (Int32.shift_right t 24)
and b = i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 16))
and c = i32toi (Int32.logand 0x000000FFl (Int32.shift_right t 8))
and d = i32toi (Int32.logand 0x000000FFl t) in
Printf.sprintf "%C%C%C%C" (char_of_int a) (char_of_int b) (char_of_int c) (char_of_int d)
let tag_cmap = 1668112752l
and tag_glyf = 1735162214l
and tag_maxp = 1835104368l
and tag_loca = 1819239265l
and tag_head = 1751474532l
let read_format_6_encoding_table b =
let firstCode = read_ushort b in
let entryCount = read_ushort b in
let arr = Array.make (max 256 (firstCode + entryCount)) 0 in
(* FIXME: This format can address glyphs > 255, but we don't support that
elsewhere yet --- but we read the whole format table nonethless *)
try
for x = firstCode to firstCode + entryCount - 1 do
arr.(x) <- read_ushort b
done;
arr
with
e -> failwith ("bad format 6 table: " ^ Printexc.to_string e ^ "\n")
let read_encoding_table fmt length version b =
match fmt with
| 0 -> Array.init 256 (function _ -> read_byte b)
| 6 -> read_format_6_encoding_table b
| n -> if !dbg then Printf.printf "read_encoding_table: format %i not known\n" n; [||]
let read_loca_table indexToLocFormat numGlyphs b =
let fix_empties arr =
for x = 1 to Array.length arr - 1 do
if arr.(x) = arr.(x - 1) then arr.(x - 1) <- -1l
done;
if arr <> [||] then arr.(Array.length arr - 1) <- -1l
in
match indexToLocFormat with
| 0 ->
let arr = Array.init (numGlyphs + 1) (function _ -> i32ofi (read_ushort b * 2)) in
fix_empties arr; arr
| 1 ->
let arr = Array.init (numGlyphs + 1) (function _ -> read_ulong b) in
fix_empties arr; arr
| _ -> raise (Pdf.PDFError "Unknown indexToLocFormat in read_loca_table")
(* NB. Global *)
let lastval = ref (false, false, false, false, false)
let repeats = ref 0
(* Read the flags for pts points *)
let rec read_flags flags b pts =
if pts <= 0 then rev flags else
let getsingle () =
if !repeats > 0 then
begin
repeats := !repeats - 1;
!lastval
end
else
let flag = read_byte b in
let oncurve, xshort, yshort, rp, xsame, ysame =
flag land 0b00_00_00_01 = 0b1,
flag land 0b00_00_00_10 = 0b10,
flag land 0b00_00_01_00 = 0b1_00,
flag land 0b00_00_10_00 = 0b10_00,
flag land 0b00_01_00_00 = 0b1_00_00,
flag land 0b00_10_00_00 = 0b10_00_00
in
if !dbg then
Printf.printf
"flag has on curve %b, xshort %b, yshort %b, repeat %b, xsame %b, ysame %b\n"
oncurve xshort yshort rp xsame ysame;
if rp then
begin
let rs = read_byte b in
if !dbg then Printf.printf "There are %i repeats of this flag...\n" rs;
repeats := rs;
lastval := (oncurve, xshort, yshort, xsame, ysame);
!lastval
end
else
(oncurve, xshort, yshort, xsame, ysame)
in
read_flags (getsingle ()::flags) b (pts - 1)
let read_flags = read_flags []
(* NB. Global. *)
let prev = ref 0
(* NB. Set up prev before calling for each glyph *)
let read_coordinates b flags =
map
(function (*short, same *)
| true, false -> prev := !prev - read_byte b; !prev
| true, true -> prev := !prev + read_byte b; !prev
| false, false -> prev := !prev + read_short b; !prev
| false, true -> !prev)
flags
(* Returns a list of lines and quadratic beziers for the input contour. Returns floats. *)
type point = float * float
type part =
| Line of point * point
| QuadBezier of point * point * point
let rec break_coordinates_inner prev = function
| (true, (x, y))::((true, (x', y')) as l)::r ->
break_coordinates_inner (Line ((x, y), (x', y'))::prev) (l::r)
| (true, (x, y))::(false, (x', y'))::((true, (x'', y'')) as l)::r ->
break_coordinates_inner (QuadBezier ((x, y), (x', y'), (x'', y''))::prev) (l::r)
| (true, (x, y))::(false, (x', y'))::((false, (x'', y'')) as l)::r ->
let midpoint = ((x' +. x'') /. 2., (y' +. y'') /. 2.) in
break_coordinates_inner ((QuadBezier ((x, y), (x', y'), midpoint))::prev) ((true, midpoint)::l::r)
| [_] -> rev prev
| _ -> (*if !dbg then*) flprint "break_coordinated_inner: unrecognized sequence\n"; rev prev
(* FIXME: The truetype spec says that any combination of on and off points is
ok, but our conversion relies on the pattern (true + zero or more false) being
repeated.
Strategy: We can special case when all are false (ignore it), and
otherwise cycle the list until a true is first. Then we have just reduced the
problem to not being able to do anything when all points are off the curve. *)
let rec all_points_off = function
[] -> true
| (false, _)::t -> all_points_off t
| (true, _)::_ -> false
let rec cycle_true_first = function
[] -> assert false
| (true, _) as h::t -> h::t
| (false, _) as h::t -> cycle_true_first (t @ [h])
let break_coordinates = function
| [] -> []
| [_] -> []
| l ->
let tofloat (t, (x, y)) = (t, (float x, float y)) in
if all_points_off l then [] else
let closed =
match cycle_true_first l with
| [] -> assert false
| h::t -> [h] @ t @ [h]
in
break_coordinates_inner [] (map tofloat closed)
let print_unbroken_coordinates (t, (x, y)) =
Printf.printf "%b, %i, %i\n" t x y
let break_coordinates cs =
if !dbg then begin flprint "This contour:\n"; iter print_unbroken_coordinates cs end;
break_coordinates cs
let sofp (x, y) = Printf.sprintf "(%f, %f)" x y
let string_of_coordinate = function
| Line (p, p') -> Printf.sprintf "Line %s --> %s\n" (sofp p) (sofp p')
| QuadBezier (p, p', p'') -> Printf.sprintf "QuadBezier %s --> %s --> %s\n" (sofp p) (sofp p') (sofp p'')
let print_coordinates =
iter (function x -> flprint (string_of_coordinate x))
(* Cubic bezier from quadratic bezier *)
let mkcubicbezier (p0x, p0y) (p1x, p1y) (p2x, p2y) =
let cp1x = p0x +. ((2. /. 3.) *. (p1x -. p0x))
and cp1y = p0y +. ((2. /. 3.) *. (p1y -. p0y))
and cp2x = p2x +. ((2. /. 3.) *. (p1x -. p2x))
and cp2y = p2y +. ((2. /. 3.) *. (p1y -. p2y)) in
Pdfgraphics.Bezier ((p0x, p0y), (cp1x, cp1y), (cp2x, cp2y), (p2x, p2y))
let graphic_of_contours contours =
{Pdfgraphics.elements =
[Pdfgraphics.Path
((Pdfgraphics.NonZero,
map
(function bits -> Pdfgraphics.Not_hole, Pdfgraphics.Closed, bits)
(map_lol
(function
| Line (p, p') -> Pdfgraphics.Straight (p, p')
| QuadBezier (p, p', p'') -> mkcubicbezier p p' p'')
contours)),
{Pdfgraphics.path_transform = Pdftransform.i_matrix;
Pdfgraphics.path_fill = Some (Pdfspace.DeviceGray, Pdfgraphics.Floats [1.]);
Pdfgraphics.path_line = None;
Pdfgraphics.path_linewidth = 0.;
Pdfgraphics.path_joinstyle = 0;
Pdfgraphics.path_capstyle = 0;
Pdfgraphics.path_dash = ([0.], 0.);
Pdfgraphics.path_mitrelimit = 0.;
Pdfgraphics.path_transparency = {Pdfgraphics.fill_transparency = 1.; Pdfgraphics.line_transparency = 1.};
Pdfgraphics.path_intent = "/RelativeColorimetric"})];
Pdfgraphics.fonts = [];
Pdfgraphics.resources = Pdf.Dictionary []}
let merge_components graphics =
{Pdfgraphics.elements = flatten (map (fun g -> g.Pdfgraphics.elements) graphics);
Pdfgraphics.fonts = [];
Pdfgraphics.resources = Pdf.Dictionary []}
let arg_1_and_2_are_words = 0b1
and args_are_xy_values = 0b10
and round_xy_to_grid = 0b100
and we_have_a_scale = 0b1000
and more_components = 0b100000
and we_have_an_x_and_y_scale = 0b1000000
and we_have_a_two_by_two = 0b10000000
and we_have_instructions = 0b100000000
and use_my_metrics = 0b1000000000
(* FIXME: Missing things: WE_HAVE_A_2_BY_2 and WE_HAVE_AND_XY_SCALE missing.
Also, args_are_xy_values false ==> points not values - need examples of all
these three *)
let rec read_composite_glyph rg b =
let graphics = ref [] in
if !dbg then flprint "reading composite glyph...\n";
let xmin = read_fword b in
let ymin = read_fword b in
let xmax = read_fword b in
let ymax = read_fword b in
if !dbg then Printf.printf "xmin, ymin, xmax, ymax = %i, %i, %i, %i\n" xmin ymin xmax ymax;
let finished = ref false in
while not !finished do
let flags = read_ushort b in
let glyphIndex = read_ushort b in
if !dbg then Printf.printf "flags = %i, glyph_index = %i\n" flags glyphIndex;
let argument1, argument2 =
if (flags land arg_1_and_2_are_words) > 0 then
let one = read_short b in
let two = read_short b in
one, two
else
let v = read_ushort b in
v lsr 8, v land 255
in
if !dbg then Printf.printf "arg1 = %i, arg2 = %i\n" argument1 argument2;
begin if (flags land we_have_a_scale) > 0 then
let scale = read_f2dot14 b in
if !dbg then Printf.printf "have read scale %f\n" scale;
let currpos = Pdfio.bitstream_pos b in
let graphic = rg glyphIndex in
Pdfio.bitstream_seek b currpos;
let transformed =
Pdfgraphics.transform_graphic
(Pdftransform.matrix_of_transform
[Pdftransform.Translate (float_of_int argument1, float_of_int argument2);
Pdftransform.Scale ((0., 0.), scale, scale)])
graphic
in
graphics := transformed::!graphics
else if (flags land we_have_an_x_and_y_scale) > 0 then
let xscale = read_f2dot14 b in
let yscale = read_f2dot14 b in
if !dbg then Printf.printf "read scales %f, %f\n" xscale yscale;
else if (flags land we_have_a_two_by_two) > 0 then
let xscale = read_f2dot14 b in
let scale01 = read_f2dot14 b in
let scale10 = read_f2dot14 b in
let yscale = read_f2dot14 b in
if !dbg then Printf.printf "read scalesss %f, %f, %f, %f\n" xscale scale01 scale10 yscale
else
if !dbg then flprint "no scale\n";
let currpos = Pdfio.bitstream_pos b in
let graphic = rg glyphIndex in
Pdfio.bitstream_seek b currpos;
let moved_graphic =
Pdfgraphics.transform_graphic
(Pdftransform.mktranslate (float_of_int argument1) (float_of_int argument2))
graphic
in
graphics := moved_graphic::!graphics
end;
if (flags land more_components) = 0 then set finished
done;
if !dbg then Printf.printf "We have read %i composite glyph components\n" (length !graphics);
merge_components !graphics
and read_glyph rg b =
let numberOfContours = read_short b in
match numberOfContours with
| 0 -> notdef
| -1 -> read_composite_glyph rg b
| x when x < -1 -> raise (Pdf.PDFError "Unknown numberOfContours")
| _ ->
let xMin = read_fword b in
let yMin = read_fword b in
let xMax = read_fword b in
let yMax = read_fword b in
if !dbg then
Printf.printf "numberOfContours = %i, xmin = %i, ymin = %i, xmax = %i, ymax = %i\n" numberOfContours xMin yMin xMax yMax;
let endPtsOfContours = Array.init numberOfContours (function _ -> read_ushort b) in
if !dbg then
(Printf.printf "endPtsOfContours:"; Array.iter (Printf.printf "%i ") endPtsOfContours; flprint "\n");
let pointstoread =
(endPtsOfContours.(0) + 1)::couple (fun x y -> y - x) (Array.to_list endPtsOfContours)
in
let instructionLength = read_ushort b in
if !dbg then Printf.printf "instructionLength is %i\n" instructionLength;
let _ = Array.init instructionLength (function _ -> read_byte b) in
(* Read a list of lists of (on/off, x is short/long, y is short/long, xsame, ysame) triples *)
if !dbg then Printf.printf "Reading flags...\n";
let flags =
map
(fun pts -> if !dbg then Printf.printf "to read: flags for %i pts on a contour:\n" pts; read_flags b pts)
pointstoread
in
prev := 0;
repeats := 0;
if !dbg then Printf.printf "Reading x coordinates\n";
let xcoords = map (fun flags -> read_coordinates b (map (fun (_, xs, _, xsame, _) -> (xs, xsame)) flags)) flags in
prev := 0;
repeats := 0;
if !dbg then Printf.printf "Reading y coordinates\n";
let ycoords = map (fun flags -> read_coordinates b (map (fun (_, _, ys, _, ysame) -> (ys, ysame)) flags)) flags in
let contours = List.map2 combine xcoords ycoords in
let pairs =
if length flags <> length contours
then raise (Pdf.PDFError "bad flags / contours in truetype font")
else combine (map_lol (fun (on, _, _, _, _) -> on) flags) contours
in
graphic_of_contours (map break_coordinates (map (function (a, b) -> combine a b) pairs))
let read_glyph rg b =
try read_glyph rg b with
e ->
if !dbg then Printf.printf "Failed to read glyph with %s\n" (Printexc.to_string e);
graphic_of_contours []
let parse_truetype_font data =
(*if !dbgg then ignore (Graphics.open_graph " 1024x1024");*)
let mk_b byte_offset = bitbytes_of_input (let i = input_of_bytes data in i.seek_in byte_offset; i) in
let b = mk_b 0 in
let major, minor = read_fixed b in
if !dbg then Printf.printf "Truetype font version %i.%i\n" major minor;
let numTables = read_ushort b in
let searchRange = read_ushort b in
let entrySelector = read_ushort b in
let rangeShift = read_ushort b in
if !dbg then Printf.printf "numTables = %i, searchRange = %i, entrySelector = %i, rangeShift = %i\n"
numTables searchRange entrySelector rangeShift;
let tables = ref [] in
for x = 1 to numTables do
let tag = read_ulong b in
let checkSum = read_ulong b in
let offset = read_ulong b in
let ttlength = read_ulong b in
if !dbg then Printf.printf "tag = %li = %s, checkSum = %li, offset = %li, ttlength = %li\n"
tag (string_of_tag tag) checkSum offset ttlength;
tables =| (tag, checkSum, offset, ttlength);
done;
let cmap =
match keep (function (t, _, _, _) -> t = tag_cmap) !tables with
| (_, _, o, l)::_ -> Some (o, l)
| [] -> None
in
let glyphcodes = ref [] in
begin match cmap with
| None ->
glyphcodes := ilist 0 255
| Some (cmapoffset, cmaplength) ->
let b = mk_b (i32toi cmapoffset) in
let cmap_version = read_ushort b in
let num_encoding_tables = read_ushort b in
if !dbg then Printf.printf "cmap version %i. There are %i encoding tables\n"
cmap_version num_encoding_tables;
for x = 1 to num_encoding_tables do
let platform_id = read_ushort b in
let encoding_id = read_ushort b in
let subtable_offset = read_ulong b in
if !dbg then Printf.printf "subtable %i. platform_id = %i, encoding_id = %i, subtable_offset = %li\n"
x platform_id encoding_id subtable_offset;
let b = mk_b (i32toi cmapoffset + i32toi subtable_offset) in
let fmt = read_ushort b in
let lngth = read_ushort b in
let version = read_ushort b in
if !dbg then Printf.printf "subtable has format %i, length %i, version %i\n" fmt lngth version;
let got_glyphcodes = read_encoding_table fmt length version b in
if !glyphcodes = [] && got_glyphcodes <> [||] then
(if !dbg then flprint "USING THIS TABLE\n"; glyphcodes := Array.to_list got_glyphcodes);
if !dbg && got_glyphcodes <> [||] then
array_iter2 (Printf.printf "charcode %i --> glyphcode %i\n") (Array.of_list (ilist 0 255)) got_glyphcodes
done;
end;
let maxpoffset, maxplength =
match keep (function (t, _, _, _) -> t = tag_maxp) !tables with
| (_, _, o, l)::_ -> o, l
| [] -> raise (Pdf.PDFError "No maxp table found in TrueType font")
in
let b = mk_b (i32toi maxpoffset) in
let major, minor = read_fixed b in
let numGlyphs = read_ushort b in
if !dbg then Printf.printf "maxp table version %i.%i: This font has %i glyphs\n" major minor numGlyphs;
let headoffset, headlength =
match keep (function (t, _, _, _) -> t = tag_head) !tables with
| (_, _, o, l)::_ -> o, l
| [] -> raise (Pdf.PDFError "No maxp table found in TrueType font")
in
let b = mk_b (i32toi headoffset) in
let _ (*major, minor*) = read_fixed b in
let _ (*revmajor, revminor*) = read_fixed b in
let _ (*checkSumAdjustment*) = read_ulong b in
let _ (*magicNumber*) = read_ulong b in
let _ (*flags*) = read_ushort b in
let unitsPerEm = read_ushort b in
let _ (*created*) = read_longdatetime b in
let _ (*modified*) = read_longdatetime b in
let _ (*xMin*) = read_fword b in
let _ (*yMin*) = read_fword b in
let _ (*xMax*) = read_fword b in
let _ (*yMax*) = read_fword b in
let _ (*macStyle*) = read_ushort b in
let _ (*lowestRecPPEM*) = read_ushort b in
let _ (*fontDirectionHint*) = read_short b in
let indexToLocFormat = read_short b in
let _ (*glyphDataFormat*) = read_short b in
if !dbg then Printf.printf "head table: indexToLocFormat is %i\n" indexToLocFormat;
let locaoffset, localength =
match keep (function (t, _, _, _) -> t = tag_loca) !tables with
| (_, _, o, l)::_ -> o, l
| [] -> raise (Pdf.PDFError "No maxp table found in TrueType font")
in
let b = mk_b (i32toi locaoffset) in
let offsets = read_loca_table indexToLocFormat numGlyphs b in
if !dbg then
begin
Printf.printf "Have read loca table:\n";
array_iter2 (Printf.printf "Glyph %i is at offset %li\n") (Array.of_list (ilist 0 numGlyphs)) offsets;
flush stdout
end;
let glyfoffset, glyflength =
match keep (function (t, _, _, _) -> t = tag_glyf) !tables with
| (_, _, o, l)::_ -> o, l
| [] -> raise (Pdf.PDFError "No glyf table found in TrueType font")
in
let glyphcache = Hashtbl.create 300 in
let glyphs =
Array.to_list
(Array.map
(function offset ->
if offset = -1l then notdef else
try Hashtbl.find glyphcache offset with
Not_found ->
let r =
let b = mk_b (i32toi glyfoffset + i32toi offset) in
read_glyph
(* Build the function reads a glyph from an offset. Gross. *)
(fun glyphnum ->
if !dbg then Printf.printf "READING GLYPH NUMBER %i\n" glyphnum;
try
let offset = offsets.(glyphnum) in
if offset = -1l then notdef else
try Hashtbl.find glyphcache offset with
Not_found ->
let b = mk_b (i32toi glyfoffset + i32toi offset) in
let r =
read_glyph (fun _ -> flprint "too much font recursion"; notdef (* FIXME *)) b
in
Hashtbl.add glyphcache offset r;
r
with
_ -> flprint "Failed component read\n"; notdef)
b
in
Hashtbl.add glyphcache offset r;
r)
offsets)
in
if !dbg then Printf.printf "Read %i glyphs\n" (length glyphs);
(map
(function incode ->
(*Printf.printf "So, incode %i " incode;*)
let glyphcode = List.nth !glyphcodes incode in
(*Printf.printf "is glyphcode %i \n" glyphcode;*)
try List.nth glyphs glyphcode
with _ ->
if !dbg then
Printf.printf
"ERROR: no glyph for incode %i which is glyphcode %i - substituting notdef\n" incode glyphcode;
notdef)
(ilist 0 255)),
(let scale = 1.0 /. (float_of_int unitsPerEm) in
Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), scale, scale)))
(* Make a CharProc stream from a graphic. We need to filter out ops we don't
want. *)
let charprocbytes_of_graphic g matrix =
Pdfops.stream_of_ops
(Pdfops.Op_d1 (0., 0., 0., 0., 0., 0.)::
lose
(function
| Pdfops.Op_q | Pdfops.Op_Q | Pdfops.Op_cm _ | Pdfops.Op_w _
| Pdfops.Op_J _ | Pdfops.Op_j _ | Pdfops.Op_M _ | Pdfops.Op_ri _
| Pdfops.Op_CS _ | Pdfops.Op_SCN _ | Pdfops.Op_cs _
| Pdfops.Op_scn _ -> true
| _ -> false)
(Pdfgraphics.ops_of_simple_graphic (Pdfgraphics.transform_graphic matrix g)))
let to_type3 pdf font =
match font with
| Pdftext.SimpleFont
({Pdftext.fonttype = Pdftext.Truetype;
Pdftext.encoding = original_encoding;
Pdftext.fontdescriptor =
Some ({Pdftext.fontfile = Some Pdftext.FontFile2 fontfileobj} as fontdescriptor)} as fontrec) ->
let glyphs, fontmatrix =
let str = Pdf.direct pdf (Pdf.Indirect fontfileobj) in
Pdfcodec.decode_pdfstream pdf str;
match str with
| Pdf.Stream {contents = (_, Pdf.Got data)} ->
begin try parse_truetype_font data with
e -> Printf.printf "Error %s" (Printexc.to_string e); raise (Pdf.PDFError "TrueType failure")
end
| _ -> raise (Pdf.PDFError "Truetype data not a stream")
in
let charprocs =
let scalematrix =
Pdftransform.matrix_compose
fontmatrix
(Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 1000., 1000.)))
in
map2
(fun n g ->
"/" ^ string_of_int n, Pdf.Indirect (Pdf.addobj pdf (charprocbytes_of_graphic g scalematrix)))
(ilist 0 (length glyphs - 1))
glyphs
and fontmatrix =
Pdftransform.matrix_of_op (Pdftransform.Scale ((0., 0.), 0.001, 0.001))
and fontbbox =
(0., 0., 0., 0.)
and encoding =
Pdftext.CustomEncoding (Pdftext.ImplicitInFontFile, [])
in
Pdftext.SimpleFont
{fontrec with
Pdftext.fonttype = Pdftext.Type3
{Pdftext.fontbbox = fontbbox;
Pdftext.fontmatrix = fontmatrix;
Pdftext.charprocs = charprocs;
Pdftext.type3_resources = Pdf.Dictionary []};
Pdftext.encoding = encoding;
Pdftext.fontdescriptor = Some fontdescriptor}
| _ ->
raise (Pdf.PDFError "Pdftruetype.to_type3: This is not a TrueType font")
(* let iround f = int_of_float (floor f) / 3 + 100 in
flprint "This glyph:\n";
iter
(fun (flags, coords) ->
flprint "This contour:\n";
iter2
(fun on (x, y) ->
Printf.printf "on = %b, point = (%i, %i)\n" on x y;
Graphics.set_color (if on then Graphics.blue else Graphics.red);
Graphics.draw_circle (iround (float x) + 200) ((iround (float y)) + 200) 10)
flags
coords;
let broken = break_coordinates (combine flags coords) in
print_coordinates broken;
if !dbgg then
begin
Graphics.set_color Graphics.black;
iter
(function
| Line ((x, y), (x', y')) ->
Graphics.moveto (iround x + 200) (iround y + 200);
Graphics.lineto (iround x' + 200) (iround y' + 200)
| QuadBezier ((x, y), (x', y'), (x'', y'')) ->
let Pdfgraphics.Bezier ((ax, ay), (bx, by), (cx, cy), (dx, dy)) = mkcubicbezier (x, y) (x', y') (x'', y'') in
Graphics.moveto (iround ax + 200) (iround ay + 200);
Graphics.curveto
(iround bx + 200, iround by + 200) (iround cx + 200, iround cy + 200) (iround dx + 200, iround dy + 200))
broken
end;
)
pairs;
(*graphic_of_contours broken*)
if !dbgg then
begin
ignore (Graphics.wait_next_event [Graphics.Key_pressed]);
Graphics.clear_graph ();
end;*)