# ttfglyph2svg # Copyright (C) 2006 Mathieu Blondel # # This program is free software; you can redistribute it and/or modify # it under the terms of the GNU General Public License as published by # the Free Software Foundation; either version 2 of the License, or # (at your option) any later version. # # This program is distributed in the hope that it will be useful, # but WITHOUT ANY WARRANTY; without even the implied warranty of # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the # GNU General Public License for more details. # # You should have received a copy of the GNU General Public License # along with this program; if not, write to the Free Software # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA $LOAD_PATH.unshift("../lib/") require 'ttf' def puts_svg_header puts < XML end def puts_svg_footer puts "" end def puts_simple_glyph(glyph) points = glyph.points puts "" print " max_y if start_new_contour # The -y is needed because the directions of the y-axis # with SVG and TrueType are opposed. print "M#{points[i].abs_x} #{-(points[i].abs_y)}" first_point = points[i] end if points[i].end_of_contour? print "Z" start_new_contour = true i += 1 else if points[i].on_curve? and points[i + 1].on_curve? print "L#{points[i + 1].abs_x} #{-(points[i + 1].abs_y)}" i += 1 else if points[i + 1].end_of_contour? # Close the contour print "Q#{points[i + 1].abs_x} " + \ "#{-(points[i + 1].abs_y)} " + \ "#{first_point.abs_x} #{-(first_point.abs_y)}" i += 1 elsif points[i + 2].on_curve? print "Q#{points[i + 1].abs_x} " + \ "#{-(points[i + 1].abs_y)} " + \ "#{points[i + 2].abs_x} #{-(points[i + 2].abs_y)}" i += 2 else # This is an implied on-curve point impl_x = (points[i + 2].abs_x - points[i + 1].abs_x) / 2 impl_x += points[i + 1].abs_x impl_y = (points[i + 2].abs_y - points[i + 1].abs_y) / 2 impl_y += points[i + 1].abs_y print "Q#{points[i + 1].abs_x} " + \ "#{-(points[i + 1].abs_y)} " + \ "#{impl_x} #{-(impl_y)}" i += 1 end end start_new_contour = false end end puts "\" transform=\"translate(0, #{max_y + 10})\" " + \ "style=\"fill:black;stroke:black;\"/>/>" puts "" end def puts_composite_glyph(font, glyph) glyph_offsets = font.get_table(:loca).glyph_offsets glyph.components.each do |gc| gc = font.get_table(:glyf).get_glyph_at_offset(glyph_offsets[gc.index]) if gc.composite? puts_composite_glyph(font, gc) else puts_simple_glyph(gc) end end end font = TTFFont::TTF::File.new(ARGV[0]) enc_tbl = font.get_table(:cmap).encoding_tables.find do |t| t.class == TTFFont::TTF::Table::Cmap::EncodingTable4 end if ARGV[1] == "-g" offs = font.get_table(:loca).glyph_offsets[ARGV[2].to_i] glyph = font.get_table(:glyf).get_glyph_at_offset(offs) elsif ARGV[1] == "-c" char_code = ARGV[2].unpack("U")[0] glyph = enc_tbl.get_glyph_for_unicode(char_code) else exit! end puts_svg_header if glyph.simple? puts_simple_glyph(glyph) else puts_composite_glyph(font, glyph) end puts_svg_footer