tTFSwfWriter.ml 6.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211
  1. (*
  2. * Copyright (C)2005-2014 Haxe Foundation
  3. *
  4. * Permission is hereby granted, free of charge, to any person obtaining a
  5. * copy of this software and associated documentation files (the "Software"),
  6. * to deal in the Software without restriction, including without limitation
  7. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  8. * and/or sell copies of the Software, and to permit persons to whom the
  9. * Software is furnished to do so, subject to the following conditions:
  10. *
  11. * The above copyright notice and this permission notice shall be included in
  12. * all copies or substantial portions of the Software.
  13. *
  14. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  20. * DEALINGS IN THE SOFTWARE.
  21. *)
  22. open TTFData
  23. open Swf
  24. let num_bits x =
  25. if x = 0 then
  26. 0
  27. else
  28. let rec loop n v =
  29. if v = 0 then n else loop (n + 1) (v lsr 1)
  30. in
  31. loop 1 (abs x)
  32. let round x = int_of_float (floor (x +. 0.5))
  33. let to_twips v = round (v *. 20.)
  34. type ctx = {
  35. ttf : ttf;
  36. }
  37. let begin_fill =
  38. SRStyleChange {
  39. scsr_move = None;
  40. scsr_fs0 = Some(1);
  41. scsr_fs1 = None;
  42. scsr_ls = None;
  43. scsr_new_styles = None;
  44. }
  45. let end_fill =
  46. SRStyleChange {
  47. scsr_move = None;
  48. scsr_fs0 = None;
  49. scsr_fs1 = None;
  50. scsr_ls = None;
  51. scsr_new_styles = None;
  52. }
  53. let align_bits x nbits = x land ((1 lsl nbits ) - 1)
  54. let move_to ctx x y =
  55. let x = to_twips x in
  56. let y = to_twips y in
  57. let nbits = max (num_bits x) (num_bits y) in
  58. SRStyleChange {
  59. scsr_move = Some (nbits, align_bits x nbits, align_bits y nbits);
  60. scsr_fs0 = Some(1);
  61. scsr_fs1 = None;
  62. scsr_ls = None;
  63. scsr_new_styles = None;
  64. }
  65. let line_to ctx x y =
  66. let x = to_twips x in
  67. let y = to_twips y in
  68. if x = 0 && y = 0 then raise Exit;
  69. let nbits = max (num_bits x) (num_bits y) in
  70. SRStraightEdge {
  71. sser_nbits = nbits;
  72. sser_line = (if x = 0 then None else Some(align_bits x nbits)), (if y = 0 then None else Some(align_bits y nbits));
  73. }
  74. let curve_to ctx cx cy ax ay =
  75. let cx = to_twips cx in
  76. let cy = to_twips cy in
  77. let ax = to_twips ax in
  78. let ay = to_twips ay in
  79. let nbits = max (max (num_bits cx) (num_bits cy)) (max (num_bits ax) (num_bits ay)) in
  80. SRCurvedEdge {
  81. scer_nbits = nbits;
  82. scer_cx = align_bits cx nbits;
  83. scer_cy = align_bits cy nbits;
  84. scer_ax = align_bits ax nbits;
  85. scer_ay = align_bits ay nbits;
  86. }
  87. open TTFTools
  88. let write_paths ctx paths =
  89. let scale = 1024. /. (float_of_int ctx.ttf.ttf_head.hd_units_per_em) in
  90. let srl = DynArray.create () in
  91. List.iter (fun path ->
  92. try
  93. DynArray.add srl (match path.gp_type with
  94. | 0 -> move_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
  95. | 1 -> line_to ctx (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
  96. | 2 -> curve_to ctx (path.gp_cx *. scale) ((-1.) *. path.gp_cy *. scale) (path.gp_x *. scale) ((-1.) *. path.gp_y *. scale);
  97. | _ -> assert false)
  98. with Exit ->
  99. ()
  100. ) paths;
  101. DynArray.add srl (end_fill);
  102. {
  103. srs_nfbits = 1;
  104. srs_nlbits = 0;
  105. srs_records = DynArray.to_list srl;
  106. }
  107. let rec write_glyph ctx key glyf =
  108. {
  109. font_char_code = key;
  110. font_shape = write_paths ctx (TTFTools.build_glyph_paths ctx.ttf true glyf);
  111. }
  112. let write_font_layout ctx lut =
  113. let scale = 1024. /. (float_of_int ctx.ttf.ttf_head.hd_units_per_em) in
  114. let hmtx = Hashtbl.fold (fun k v acc -> (k,ctx.ttf.ttf_hmtx.(v)) :: acc) lut [] in
  115. let hmtx = List.stable_sort (fun a b -> compare (fst a) (fst b)) hmtx in
  116. let hmtx = List.map (fun (k,g) -> g) hmtx in
  117. {
  118. font_ascent = round((float_of_int ctx.ttf.ttf_os2.os2_us_win_ascent) *. scale *. 20.);
  119. font_descent = round((float_of_int ctx.ttf.ttf_os2.os2_us_win_descent) *. scale *. 20.);
  120. font_leading = round(((float_of_int(ctx.ttf.ttf_os2.os2_us_win_ascent + ctx.ttf.ttf_os2.os2_us_win_descent - ctx.ttf.ttf_head.hd_units_per_em)) *. scale) *. 20.);
  121. font_glyphs_layout = Array.of_list( ExtList.List.mapi (fun i h ->
  122. {
  123. font_advance = round((float_of_int h.advance_width) *. scale *. 20.);
  124. font_bounds = {rect_nbits=0; left=0; right=0; top=0; bottom=0};
  125. }) hmtx );
  126. font_kerning = [];
  127. }
  128. let bi v = if v then 1 else 0
  129. let int_from_langcode lc =
  130. match lc with
  131. | LCNone -> 0
  132. | LCLatin -> 1
  133. | LCJapanese -> 2
  134. | LCKorean -> 3
  135. | LCSimplifiedChinese -> 4
  136. | LCTraditionalChinese -> 5
  137. let write_font2 ch b f2 =
  138. IO.write_bits b 1 (bi true);
  139. IO.write_bits b 1 (bi f2.font_shift_jis);
  140. IO.write_bits b 1 (bi f2.font_is_small);
  141. IO.write_bits b 1 (bi f2.font_is_ansi);
  142. IO.write_bits b 1 (bi f2.font_wide_offsets);
  143. IO.write_bits b 1 (bi f2.font_wide_codes);
  144. IO.write_bits b 1 (bi f2.font_is_italic);
  145. IO.write_bits b 1 (bi f2.font_is_bold);
  146. IO.write_byte ch (int_from_langcode f2.font_language);
  147. IO.write_byte ch ((String.length f2.font_name) + 1);
  148. IO.nwrite_string ch f2.font_name;
  149. IO.write_byte ch 0;
  150. IO.write_ui16 ch (Array.length f2.font_glyphs);
  151. let glyph_offset = ref (((Array.length f2.font_glyphs) * 4)+4) in
  152. Array.iter (fun g ->
  153. IO.write_i32 ch !glyph_offset;
  154. glyph_offset := !glyph_offset + SwfParser.font_shape_records_length g.font_shape;
  155. )f2.font_glyphs;
  156. IO.write_i32 ch !glyph_offset;
  157. Array.iter (fun g -> SwfParser.write_shape_without_style ch g.font_shape;) f2.font_glyphs;
  158. Array.iter (fun g -> IO.write_ui16 ch g.font_char_code; )f2.font_glyphs;
  159. IO.write_i16 ch f2.font_layout.font_ascent;
  160. IO.write_i16 ch f2.font_layout.font_descent;
  161. IO.write_i16 ch f2.font_layout.font_leading;
  162. Array.iter (fun g ->
  163. let fa = ref g.font_advance in
  164. if (!fa) < -32767 then fa := -32768;(* fix or check *)
  165. if (!fa) > 32766 then fa := 32767;
  166. IO.write_i16 ch !fa;) f2.font_layout.font_glyphs_layout;
  167. Array.iter (fun g -> SwfParser.write_rect ch g.font_bounds;) f2.font_layout.font_glyphs_layout;
  168. IO.write_ui16 ch 0 (* TODO: optional FontKerningTable *)
  169. let to_swf ttf config =
  170. let ctx = {
  171. ttf = ttf;
  172. } in
  173. let lut = TTFTools.build_lut ttf config.ttfc_range_str in
  174. let glyfs = Hashtbl.fold (fun k v acc -> (k,ctx.ttf.ttf_glyfs.(v)) :: acc) lut [] in
  175. let glyfs = List.stable_sort (fun a b -> compare (fst a) (fst b)) glyfs in
  176. let glyfs = List.map (fun (k,g) -> write_glyph ctx k g) glyfs in
  177. let glyfs_font_layout = write_font_layout ctx lut in
  178. let glyfs = Array.of_list glyfs in
  179. {
  180. font_shift_jis = false;
  181. font_is_small = false;
  182. font_is_ansi = false;
  183. font_wide_offsets = true;
  184. font_wide_codes = true;
  185. font_is_italic = config.ttfc_font_posture = TFPItalic;
  186. font_is_bold = config.ttfc_font_weight = TFWBold;
  187. font_language = LCNone;
  188. font_name = (match config.ttfc_font_name with Some s -> s | None -> ttf.ttf_font_name);
  189. font_glyphs = glyfs;
  190. font_layout = glyfs_font_layout;
  191. }
  192. ;;