From 2514b6493d7f78e2fb9a7f1107209d3c443018a3 Mon Sep 17 00:00:00 2001 From: Matthew Butterick Date: Mon, 19 Jun 2017 12:03:38 -0700 Subject: [PATCH] subset with composites --- pitfall/fontkit/subset.rkt | 16 ++++--- pitfall/fontkit/ttfglyph.rkt | 55 +++++++++++++++++++++-- pitfall/pitfall/test/out.bin | Bin 4199 -> 3373 bytes pitfall/pitfall/test/test13.coffee | 23 ++++++++++ pitfall/pitfall/test/test13.pdf | Bin 0 -> 5418 bytes pitfall/pitfall/test/test13.rkt | 27 +++++++++++ pitfall/pitfall/test/test13crkt copy.pdf | Bin 0 -> 4058 bytes pitfall/pitfall/test/test13crkt.pdf | Bin 0 -> 4058 bytes pitfall/pitfall/test/test13rkt copy.pdf | Bin 0 -> 5418 bytes pitfall/pitfall/test/test13rkt.pdf | Bin 0 -> 5418 bytes pitfall/restructure/stream.rkt | 4 +- 11 files changed, 114 insertions(+), 11 deletions(-) create mode 100644 pitfall/pitfall/test/test13.coffee create mode 100644 pitfall/pitfall/test/test13.pdf create mode 100644 pitfall/pitfall/test/test13.rkt create mode 100644 pitfall/pitfall/test/test13crkt copy.pdf create mode 100644 pitfall/pitfall/test/test13crkt.pdf create mode 100644 pitfall/pitfall/test/test13rkt copy.pdf create mode 100644 pitfall/pitfall/test/test13rkt.pdf diff --git a/pitfall/fontkit/subset.rkt b/pitfall/fontkit/subset.rkt index a59fa6a0..56540788 100644 --- a/pitfall/fontkit/subset.rkt +++ b/pitfall/fontkit/subset.rkt @@ -71,10 +71,12 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js ;; if it is a compound glyph, include its components (when (and glyf (negative? (· glyf numberOfContours))) - (set! buffer (+Buffer buffer)) (for ([component (in-list (· glyf components))]) - (define gid (includeGlyph (· component glyphID))) - (send buffer writUInt16BE gid (send component pos)))) + (define gid (send this includeGlyph (· component glyphID))) + (define es (+EncodeStream)) + (send uint16be encode es gid) + (bytes-copy! buffer (· component pos) (send es dump)))) + ;; skip variation shit (push-end-field! glyf this buffer) @@ -83,7 +85,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js (hash-update! (get-field hmtx this) 'metrics (λ (ms) (append ms (list (mhash 'advance (· glyph advanceWidth) - 'bearing (· (send glyph _getMetrics) leftBearing)))))) + 'bearing (· (send glyph _getMetrics) leftBearing)))))) (increment-field! offset this (bytes-length buffer)) (sub1 (length (· this glyf)))) @@ -101,7 +103,11 @@ https://github.com/mbutterick/fontkit/blob/master/src/subset/TTFSubset.js (set-field! hmtx this (mhash 'metrics empty 'bearings empty)) ;; include all the glyphs used in the document - (for ([gid (in-list (· this glyphs))]) + ;; not using `in-list` because we need to support adding more + ;; glyphs to the array as component glyphs are discovered & enqueued + (for ([idx (in-naturals)] + #:break (= idx (length (· this glyphs)))) + (define gid (list-ref (· this glyphs) idx)) (send this _addGlyph gid)) (define maxp (cloneDeep (send (· this font) _getTable 'maxp))) diff --git a/pitfall/fontkit/ttfglyph.rkt b/pitfall/fontkit/ttfglyph.rkt index 6bb98e91..63d49f9a 100644 --- a/pitfall/fontkit/ttfglyph.rkt +++ b/pitfall/fontkit/ttfglyph.rkt @@ -28,7 +28,8 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js (match-define (list ARG_1_AND_2_ARE_WORDS ARGS_ARE_XY_VALUES ROUND_XY_TO_GRID - WE_HAVE_A_SCALE + WE_HAVE_A_SCALE + ___NO-FLAG___ MORE_COMPONENTS WE_HAVE_AN_X_AND_Y_SCALE WE_HAVE_A_TWO_BY_TWO @@ -37,7 +38,7 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js OVERLAP_COMPOUND SCALED_COMPONENT_OFFSET UNSCALED_COMPONENT_OFFSET) - (map (curry expt 2) (range 12))) + (map (curry expt 2) (range 13))) ;; Represents a point in a simple glyph (define-subclass object% (Point onCurve endContour [x 0] [y 0]) @@ -149,6 +150,52 @@ https://github.com/mbutterick/fontkit/blob/master/src/glyph/TTFGlyph.js ) (define/public (_decodeComposite glyph stream [offset 0]) - (unfinished))) + ;; this is a composite glyph + (hash-set! glyph 'components empty) + (define haveInstructions #f) + (define flags MORE_COMPONENTS) + + (hash-set! glyph 'components + (for/list ([i (in-naturals)] + #:break (zero? (bitwise-and flags MORE_COMPONENTS))) + (set! flags (send uint16be decode stream)) + (define gPos (- (send stream pos) offset)) + (define glyphID (send uint16be decode stream)) + (unless haveInstructions + (set! haveInstructions (not (zero? (bitwise-and flags WE_HAVE_INSTRUCTIONS))))) + + (match-define + (list dx dy) + (let ([decoder (if (not (zero? (bitwise-and flags ARG_1_AND_2_ARE_WORDS))) int16be int8)]) + (list (send decoder decode stream) (send decoder decode stream)))) + + (define component (+Component glyphID dx dy)) + (set-field! pos component gPos) + + (cond + [(not (zero? (bitwise-and flags WE_HAVE_A_SCALE))) + (define scale (read-fixed14 stream)) + (set-field! scaleX component scale) + (set-field! scaleY component scale)] + [(not (zero? (bitwise-and flags WE_HAVE_AN_X_AND_Y_SCALE))) + (set-field! scaleX component (read-fixed14 stream)) + (set-field! scaleY component (read-fixed14 stream))] + [(not (zero? (bitwise-and flags WE_HAVE_A_TWO_BY_TWO))) + (set-field! scaleX component (read-fixed14 stream)) + (set-field! scale01 component (read-fixed14 stream)) + (set-field! scale10 component (read-fixed14 stream)) + (set-field! scaleY component (read-fixed14 stream))]) + + component)) + + haveInstructions + )) - + +(define (bytes->fixed14 b1 b2) + (/ (+ (* b1 (expt 2 8)) b2) (expt 2 14) 1.0)) + +(define (read-fixed14 stream) + (define b1 (send uint8 decode stream)) + (define b2 (send uint8 decode stream)) + (bytes->fixed14 b1 b2)) \ No newline at end of file diff --git a/pitfall/pitfall/test/out.bin b/pitfall/pitfall/test/out.bin index f22176fe1693c4cccef0a05a9fc7347302d9613b..0be093371961d49cf800dcf09b0da8fb2770e605 100644 GIT binary patch delta 1827 zcmY*ZU5pb|6h8NM+U{<8c_8fzK=J4_PqxQJ@(WL|VfHnA({$egBvy1E|-;L)Gzvh^5JmEOw_*g1P??_jq zpNL^)U{Pc5)}{7+BL0EnIt3_BMH-{aO&X*;IdV-(kQ25=G2*0>lxvXF*P!Go-h6`w z;g7%{$v3Hl9SOhuNR!Iz-Wc}85TgdslXDF+@ zqA0vR%PYgnTIU+RW!#3XH7F%c#G79&6j@2*N^pQ1iBVn|t8q2qQi7p!sahFJs{vIp zDqC5`aK{hljm)xBOUh&-^ysH~HnGzwZ2I z-f>;lO)RsQo4UNojBBQ;#m(RU{m?r+>>Rjyb-;<8{KSK^Ou9aPoq`LNVp)A}p6eN)V$=C2iPX#}#(@ zh3CpUH|s`iPi1CSi>e_tGPz^_?6$3DF*&(!Vq*XHWOXDQ8{9Fl@X~>KbBx+;Ty`Ta zo4Lc&IEKhY{r|vN6ZhCPehYDr6(4ZJEUoo9+2U8u3w5)7kIe(5NpH3QkWv(IBqfAeLXoRt_jCR=KU1idYD-E-hKXLiQnAWD$@%tYpE3WU(T{gD%zz^&&Ge zHg;8GYKM+=rczcri67;eQC1nNmP;y|EB0iJY%XU;$0O-Od(+#a1+SSKDfLIwk!_Rv zc0XQXuS_fHgq{iZM}peK)bpOcv%A8hMqooI=-IHjwEgLj#fgc`{=%2QNqx{F#V5f4 zD(aY>1{*^(-vUaGN0f<*(r~YKF?s|f&qElaA`tE9-ifaW-8U!-jQAWh?t$m9G|+=( z9*a1_CnKwcnc`ONhnmYujg41JK&cp@!|fL$*DCV#sdThDLK3R0#3@-QlMm{NQsYY4L`1x8BANM-Ex(_FKs0#SXG7(8n8a!!+EKk!`+Nyx ztF)^@VRR`4Zy4P5qG$9%d=7{YQ7{b2uFKH=dhdF5+U42_V7u#PgJiUvfDJEgNz7Is z{7;lvJ*Fs{_MH;5EMJO+gd2)=tpI4?Phz*x2&yd%IrV_mu1+KYQR>LTgIUo88zk9c zz#YW-R-)0@gb2RySHG|Lr%tll4|e*T^`xC?anJ&od=E^zXp1OG(Z`#>4z)o|-2?y6 zshG!BOKlR^a*7VC8W}-!^jLLn&-gKLeeT=}F;oSwx9_tRN?Gq6O7V#*X>67v>^zxb j0s9;F3}TpM;dYy?(G|QmtoRxoVPP^bURYWiILZD4weE5# literal 4199 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 diff --git a/pitfall/pitfall/test/test13.coffee b/pitfall/pitfall/test/test13.coffee new file mode 100644 index 00000000..79baadf8 --- /dev/null +++ b/pitfall/pitfall/test/test13.coffee @@ -0,0 +1,23 @@ +PDFDocument = require 'pdfkit' +fs = require 'fs' + +make = (doc) -> + + # Register a font name for use later + doc.registerFont('Charter', 'assets/charter.ttf') + + # Set the font, draw some text + doc.font('Charter') + .fontSize(25) + .text('Åcçénts äre în', 100, 100, {width: false}) + + doc.end() + + +doc = new PDFDocument({compress: no}) +doc.pipe(fs.createWriteStream('test13.pdf')) +make doc + +#doc = new PDFDocument({compress: yes}) +#doc.pipe(fs.createWriteStream('test12c.pdf')) +#make doc diff --git a/pitfall/pitfall/test/test13.pdf b/pitfall/pitfall/test/test13.pdf new file mode 100644 index 0000000000000000000000000000000000000000..1c452ac22c9d8dcdfedde2c03ee748e68c8c513c GIT binary patch literal 5418 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 T&P(-H6mR&string charter-path)) + + ;; Set the font, draw some text + (send* doc + [font "Charter"] + [fontSize 25] + [text "Åcçénts äre în" 100 100 (hash 'width #f)])) + +;; test against non-subsetted font version +(define-runtime-path this "test13rkt.pdf") +(make-doc this #f proc) + +(define-runtime-path that "test13crkt.pdf") +(make-doc that #t proc #:pdfkit #f) + +#;(module+ test + (define doc (make-object PDFDocument)) + (send doc registerFont "Charter" (path->string charter-path)) + (send* doc [font "Charter"]) + (send doc pipe (open-output-string)) + (send doc end)) diff --git a/pitfall/pitfall/test/test13crkt copy.pdf b/pitfall/pitfall/test/test13crkt copy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ffcb9401f116092b5a6d97a415b00c3483e54110 GIT binary patch literal 4058 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 a8oFK=|1jQBrJM5(j@ literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test13crkt.pdf b/pitfall/pitfall/test/test13crkt.pdf new file mode 100644 index 0000000000000000000000000000000000000000..ffcb9401f116092b5a6d97a415b00c3483e54110 GIT binary patch literal 4058 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 a8oFK=|1jQBrJM5(j@ literal 0 HcmV?d00001 diff --git a/pitfall/pitfall/test/test13rkt copy.pdf b/pitfall/pitfall/test/test13rkt copy.pdf new file mode 100644 index 0000000000000000000000000000000000000000..e8fc9343d3c2aed03de29989b394ee535e583611 GIT binary patch literal 5418 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 oQ~Z$)d0;x9FESng&@Zd=^{`%#FO&)9%9I3O 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 oQ~Z$)d0;x9FESng&@