prawn 0.2.3 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (144) hide show
  1. data/README +6 -10
  2. data/Rakefile +4 -13
  3. data/data/encodings/win_ansi.txt +29 -0
  4. data/data/images/fractal.jpg +0 -0
  5. data/data/images/letterhead.jpg +0 -0
  6. data/examples/bounding_box/bounding_boxes.rb +44 -0
  7. data/examples/bounding_box/lazy_bounding_boxes.rb +28 -0
  8. data/examples/bounding_box/padded_box.rb +24 -0
  9. data/examples/{russian_boxes.rb → bounding_box/russian_boxes.rb} +9 -6
  10. data/examples/general/background.rb +20 -0
  11. data/examples/{canvas.rb → general/canvas.rb} +6 -2
  12. data/examples/general/measurement_units.rb +52 -0
  13. data/examples/{multi_page_layout.rb → general/multi_page_layout.rb} +6 -3
  14. data/examples/{page_geometry.rb → general/page_geometry.rb} +6 -2
  15. data/examples/{image.rb → graphics/basic_images.rb} +8 -4
  16. data/examples/graphics/cmyk.rb +13 -0
  17. data/examples/graphics/curves.rb +12 -0
  18. data/examples/{hexagon.rb → graphics/hexagon.rb} +5 -5
  19. data/examples/graphics/image_fit.rb +16 -0
  20. data/examples/graphics/image_flow.rb +38 -0
  21. data/examples/graphics/image_position.rb +18 -0
  22. data/examples/{line.rb → graphics/line.rb} +4 -2
  23. data/examples/{png_types.rb → graphics/png_types.rb} +4 -4
  24. data/examples/{polygons.rb → graphics/polygons.rb} +5 -4
  25. data/examples/graphics/remote_images.rb +12 -0
  26. data/examples/{ruport_helpers.rb → graphics/ruport_style_helpers.rb} +8 -5
  27. data/examples/graphics/stroke_bounds.rb +23 -0
  28. data/examples/{chinese_text_wrapping.rb → m17n/chinese_text_wrapping.rb} +7 -4
  29. data/examples/m17n/euro.rb +16 -0
  30. data/examples/m17n/sjis.rb +29 -0
  31. data/examples/m17n/utf8.rb +14 -0
  32. data/examples/m17n/win_ansi_charset.rb +55 -0
  33. data/examples/{addressbook.csv → table/addressbook.csv} +0 -0
  34. data/examples/{cell.rb → table/cell.rb} +8 -6
  35. data/examples/{currency.csv → table/currency.csv} +0 -0
  36. data/examples/{fancy_table.rb → table/fancy_table.rb} +9 -6
  37. data/examples/{ruport_formatter.rb → table/ruport_formatter.rb} +6 -3
  38. data/examples/{table.rb → table/table.rb} +6 -2
  39. data/examples/table/table_alignment.rb +18 -0
  40. data/examples/table/table_border_color.rb +17 -0
  41. data/examples/table/table_colspan.rb +19 -0
  42. data/examples/table/table_header_color.rb +19 -0
  43. data/examples/table/table_header_underline.rb +15 -0
  44. data/examples/{alignment.rb → text/alignment.rb} +5 -2
  45. data/examples/text/family_based_styling.rb +25 -0
  46. data/examples/{flowing_text_with_header_and_footer.rb → text/flowing_text_with_header_and_footer.rb} +19 -8
  47. data/examples/text/font_calculations.rb +91 -0
  48. data/examples/text/font_size.rb +34 -0
  49. data/examples/{kerning.rb → text/kerning.rb} +5 -1
  50. data/examples/text/simple_text.rb +18 -0
  51. data/examples/text/simple_text_ttf.rb +18 -0
  52. data/examples/{span.rb → text/span.rb} +5 -2
  53. data/examples/text/text_box.rb +26 -0
  54. data/examples/{text_flow.rb → text/text_flow.rb} +5 -2
  55. data/lib/prawn.rb +26 -20
  56. data/lib/prawn/compatibility.rb +5 -8
  57. data/lib/prawn/document.rb +29 -13
  58. data/lib/prawn/document/annotations.rb +63 -0
  59. data/lib/prawn/document/bounding_box.rb +18 -3
  60. data/lib/prawn/document/destinations.rb +81 -0
  61. data/lib/prawn/document/internals.rb +16 -2
  62. data/lib/prawn/document/page_geometry.rb +58 -57
  63. data/lib/prawn/document/span.rb +8 -0
  64. data/lib/prawn/document/table.rb +81 -31
  65. data/lib/prawn/document/text.rb +66 -21
  66. data/lib/prawn/document/text/box.rb +77 -0
  67. data/lib/prawn/encoding.rb +121 -0
  68. data/lib/prawn/errors.rb +4 -0
  69. data/lib/prawn/font.rb +70 -42
  70. data/lib/prawn/font/metrics.rb +64 -119
  71. data/lib/prawn/graphics.rb +105 -87
  72. data/lib/prawn/graphics/cell.rb +55 -28
  73. data/lib/prawn/graphics/color.rb +8 -0
  74. data/lib/prawn/images.rb +55 -12
  75. data/lib/prawn/images/jpg.rb +2 -1
  76. data/lib/prawn/images/png.rb +2 -1
  77. data/lib/prawn/literal_string.rb +14 -0
  78. data/lib/prawn/measurement_extensions.rb +46 -0
  79. data/lib/prawn/measurements.rb +71 -0
  80. data/lib/prawn/name_tree.rb +165 -0
  81. data/lib/prawn/pdf_object.rb +8 -1
  82. data/spec/annotations_spec.rb +90 -0
  83. data/spec/destinations_spec.rb +15 -0
  84. data/spec/document_spec.rb +39 -2
  85. data/spec/font_spec.rb +22 -0
  86. data/spec/graphics_spec.rb +99 -87
  87. data/spec/images_spec.rb +29 -1
  88. data/spec/measurement_units_spec.rb +23 -0
  89. data/spec/metrics_spec.rb +3 -2
  90. data/spec/name_tree_spec.rb +103 -0
  91. data/spec/pdf_object_spec.rb +15 -5
  92. data/spec/png_spec.rb +14 -14
  93. data/spec/spec_helper.rb +8 -6
  94. data/spec/table_spec.rb +40 -0
  95. data/spec/text_spec.rb +6 -4
  96. data/vendor/ttfunk/data/fonts/DejaVuSans.ttf +0 -0
  97. data/vendor/ttfunk/data/fonts/comicsans.ttf +0 -0
  98. data/vendor/ttfunk/example.rb +5 -0
  99. data/vendor/ttfunk/lib/ttfunk.rb +48 -0
  100. data/vendor/ttfunk/lib/ttfunk/table.rb +27 -0
  101. data/vendor/ttfunk/lib/ttfunk/table/cmap.rb +94 -0
  102. data/vendor/ttfunk/lib/ttfunk/table/directory.rb +25 -0
  103. data/vendor/ttfunk/lib/ttfunk/table/head.rb +25 -0
  104. data/vendor/ttfunk/lib/ttfunk/table/hhea.rb +27 -0
  105. data/vendor/ttfunk/lib/ttfunk/table/hmtx.rb +20 -0
  106. data/vendor/ttfunk/lib/ttfunk/table/kern.rb +48 -0
  107. data/vendor/ttfunk/lib/ttfunk/table/maxp.rb +17 -0
  108. data/vendor/ttfunk/lib/ttfunk/table/name.rb +52 -0
  109. metadata +93 -62
  110. data/examples/bounding_boxes.rb +0 -30
  111. data/examples/curves.rb +0 -10
  112. data/examples/family_based_styling.rb +0 -21
  113. data/examples/font_size.rb +0 -19
  114. data/examples/image2.rb +0 -13
  115. data/examples/image_flow.rb +0 -29
  116. data/examples/lazy_bounding_boxes.rb +0 -19
  117. data/examples/remote_images.rb +0 -7
  118. data/examples/simple_text.rb +0 -15
  119. data/examples/simple_text_ttf.rb +0 -16
  120. data/examples/sjis.rb +0 -21
  121. data/examples/utf8.rb +0 -12
  122. data/vendor/font_ttf/ttf.rb +0 -20
  123. data/vendor/font_ttf/ttf/datatypes.rb +0 -189
  124. data/vendor/font_ttf/ttf/encodings.rb +0 -140
  125. data/vendor/font_ttf/ttf/exceptions.rb +0 -28
  126. data/vendor/font_ttf/ttf/file.rb +0 -290
  127. data/vendor/font_ttf/ttf/fontchunk.rb +0 -77
  128. data/vendor/font_ttf/ttf/table/cmap.rb +0 -408
  129. data/vendor/font_ttf/ttf/table/cvt.rb +0 -49
  130. data/vendor/font_ttf/ttf/table/fpgm.rb +0 -48
  131. data/vendor/font_ttf/ttf/table/gasp.rb +0 -88
  132. data/vendor/font_ttf/ttf/table/glyf.rb +0 -452
  133. data/vendor/font_ttf/ttf/table/head.rb +0 -86
  134. data/vendor/font_ttf/ttf/table/hhea.rb +0 -96
  135. data/vendor/font_ttf/ttf/table/hmtx.rb +0 -98
  136. data/vendor/font_ttf/ttf/table/kern.rb +0 -186
  137. data/vendor/font_ttf/ttf/table/loca.rb +0 -75
  138. data/vendor/font_ttf/ttf/table/maxp.rb +0 -81
  139. data/vendor/font_ttf/ttf/table/name.rb +0 -222
  140. data/vendor/font_ttf/ttf/table/os2.rb +0 -172
  141. data/vendor/font_ttf/ttf/table/post.rb +0 -120
  142. data/vendor/font_ttf/ttf/table/prep.rb +0 -27
  143. data/vendor/font_ttf/ttf/table/vhea.rb +0 -45
  144. data/vendor/font_ttf/ttf/table/vmtx.rb +0 -36
@@ -1,28 +0,0 @@
1
- # TTF/Ruby, a library to read and write TrueType fonts in Ruby.
2
- # Copyright (C) 2006 Mathieu Blondel
3
- #
4
- # This program is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- module Font
19
- module TTF
20
-
21
- class MalformedFont < Exception
22
- end
23
-
24
- class TableMissing < Exception
25
- end
26
-
27
- end
28
- end
@@ -1,290 +0,0 @@
1
- # TTF/Ruby, a library to read and write TrueType fonts in Ruby.
2
- # Copyright (C) 2006 Mathieu Blondel
3
- #
4
- # This program is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- require 'ttf/datatypes'
19
- require 'ttf/exceptions'
20
- require 'ttf/fontchunk'
21
- require 'ttf/encodings'
22
-
23
- require 'ttf/table/cmap'
24
- require 'ttf/table/cvt'
25
- require 'ttf/table/fpgm'
26
- require 'ttf/table/gasp'
27
- require 'ttf/table/glyf'
28
- require 'ttf/table/head'
29
- require 'ttf/table/hhea'
30
- require 'ttf/table/hmtx'
31
- require 'ttf/table/kern'
32
- require 'ttf/table/loca'
33
- require 'ttf/table/maxp'
34
- require 'ttf/table/name'
35
- require 'ttf/table/os2'
36
- require 'ttf/table/post'
37
- require 'ttf/table/prep'
38
- require 'ttf/table/vhea'
39
- require 'ttf/table/vmtx'
40
-
41
- module Font
42
- module TTF
43
- # TTF/Ruby is a library to read and write TrueType fonts in Ruby.
44
- #
45
- # Author:: Mathieu Blondel
46
- # Copyright:: Copyright (c) 2006 Mathieu Blondel
47
- # License:: GPL
48
- #
49
- # This Font::TTF::File class is TTF/Ruby's main class and is a subclass
50
- # of Ruby's File class. Here is some sample code:
51
- #
52
- # require 'ttf'
53
- #
54
- # font = Font::TTF::File.new("copy.ttf")
55
- #
56
- # cmap_tbl = font.get_table(:cmap)
57
- # enc_tbl4 = cmap_tbl.encoding_tables.find { |t| t.format == 4 }
58
- # m_unicode = "m".unpack("U")[0]
59
- # glyph_id = enc_tbl4.charmaps[m_unicode]
60
- #
61
- # loca_tbl = font.get_table(:loca)
62
- # glyph_offset = loca_tbl.glyph_offsets[glyph_id]
63
- #
64
- # glyf_tbl = font.get_table(:glyf)
65
- # glyph = glyf_tbl.get_glyph_at_offset(glyph_offset)
66
- # unless glyph.composite?
67
- # glyph.abs_coordinates.each { |x, y| puts x, y }
68
- # end
69
- #
70
- # Here are the tables and their associated Symbol:
71
- #
72
- # * :cmap => Font::TTF::Table::Cmap
73
- # * :cvt => Font::TTF::Table::Cvt
74
- # * :fpgm => Font::TTF::Table::Fpgm
75
- # * :gasp => Font::TTF::Table::Gasp
76
- # * :glyf => Font::TTF::Table::Glyf
77
- # * :head => Font::TTF::Table::Head
78
- # * :hhea => Font::TTF::Table::Hhea
79
- # * :hmtx => Font::TTF::Table::Hmtx
80
- # * :kern => Font::TTF::Table::Kern
81
- # * :loca => Font::TTF::Table::Loca
82
- # * :maxp => Font::TTF::Table::Maxp
83
- # * :name => Font::TTF::Table::Name
84
- # * :"OS/2" => Font::TTF::Table::OS2
85
- # * :post => Font::TTF::Table::Post
86
- # * :prep => Font::TTF::Table::Prep
87
- # * :vhea => Font::TTF::Table::Vhea
88
- # * :vmtx => Font::TTF::Table::Vmtx
89
- #
90
- # Of course, you may modify attributes and generate a new font file.
91
- #
92
- # require "ttf"
93
- #
94
- # font = Font::TTF::File.new("file.ttf", "w")
95
- # name_tbl = font.get_table(:name)
96
- # nr = name_tbl.name_records[0]
97
- # nr.utf8_str = "blablabla"
98
- # font.write(font.dump)
99
- #
100
- class File < File
101
-
102
- TABLES = {:cmap => Font::TTF::Table::Cmap,
103
- :cvt => Font::TTF::Table::Cvt,
104
- :fpgm => Font::TTF::Table::Fpgm,
105
- :gasp => Font::TTF::Table::Gasp,
106
- :glyf => Font::TTF::Table::Glyf,
107
- :head => Font::TTF::Table::Head,
108
- :hhea => Font::TTF::Table::Hhea,
109
- :hmtx => Font::TTF::Table::Hmtx,
110
- :kern => Font::TTF::Table::Kern,
111
- :loca => Font::TTF::Table::Loca,
112
- :maxp => Font::TTF::Table::Maxp,
113
- :name => Font::TTF::Table::Name,
114
- :"OS/2" => Font::TTF::Table::OS2,
115
- :post => Font::TTF::Table::Post,
116
- :prep => Font::TTF::Table::Prep,
117
- :vhea => Font::TTF::Table::Vhea,
118
- :vmtx => Font::TTF::Table::Vmtx}
119
-
120
- DIR_ENTRY_SIZE = 4 * IO::SIZEOF_ULONG
121
-
122
- attr_reader :filename, :version, :search_range,
123
- :entry_selector, :range_shift, :table_list, :tables_infos
124
-
125
- attr_writer :version, :search_range, :entry_selector, :range_shift
126
-
127
- # Font::TTF::File being a subclass of Ruby's File class, you may
128
- # create new objects with the same parameters as Ruby's File class.
129
- #
130
- # But you may also create new objects without parameters in case you want
131
- # to create a font from scratch and you don't need to write it to a file.
132
- def initialize(*args)
133
- if args.length == 0
134
- @filename = nil
135
- @version = 0x00010000 # 1.0
136
- else
137
- super(*args)
138
- @filename = args[0]
139
- end
140
-
141
- @table_list = [] # ordered list
142
- @tables = {} # Tables are kept in this arr so we don't
143
- # have to create new objects everytime
144
- @tables_infos = {} # infos about tables present in file
145
-
146
- if not @filename.nil? and FileTest.exists? @filename
147
- begin
148
- at_offset(0) do
149
- @version = read_fixed
150
- table_num = read_ushort
151
- @search_range = read_ushort
152
- @entry_selector = read_ushort
153
- @range_shift = read_ushort
154
-
155
- table_num.times do
156
- tag = read_ulong_as_text.strip.to_sym
157
- @table_list << tag
158
- @tables_infos[tag] = {:checksum => read_ulong,
159
- :offset => read_ulong,
160
- :len => read_ulong}
161
- end
162
- end
163
- rescue
164
- raise MalformedFont
165
- end
166
- end
167
- end
168
-
169
- # Returns table associated with tag tbl_tag. It may return one of
170
- # Font::TTF::Table::* object or a Font::TTF::FontChunk object if the
171
- # table is not implemented yet by ttf-ruby.
172
- #
173
- # The table returned is kept internally so that every future call to
174
- # get_table with the same tbl_tag will return the same object.
175
- def get_table(tbl_tag)
176
- tbli = @tables_infos[tbl_tag]
177
-
178
- if @tables.include? tbl_tag
179
- @tables[tbl_tag]
180
- elsif tbli.nil?
181
- raise TableMissing, "Table #{tbl_tag.to_s} neither exists " + \
182
- "in file nor was defined by user!"
183
-
184
- elsif TABLES.include? tbl_tag
185
- @tables[tbl_tag] = \
186
- TABLES[tbl_tag].new(self, tbli[:offset], tbli[:len])
187
- else
188
- Font::TTF::FontChunk.new(self, tbli[:offset], tbli[:len])
189
- end
190
- end
191
-
192
- # Returns whether table with tag tbl_tag is already in font or not.
193
- def tables_include?(tbl_tag)
194
- @table_list.include? tbl_tag
195
- end
196
-
197
- # Gets a new empty table that then may be set with set_table.
198
- # tbl_tag is a Symbol.
199
- def get_new_table(tbl_tag)
200
- if TABLES.include? tbl_tag
201
- TABLES[tbl_tag].new(self)
202
- else
203
- Font::TTF::FontChunk.new(self)
204
- end
205
- end
206
-
207
- # Updates some member variables that change everytime a table is added
208
- # to the font.
209
- def table_list_update!
210
- @table_list.sort!
211
-
212
- res = 1
213
- power = 0
214
- while res <= @table_list.length
215
- res *= 2
216
- power += 1
217
- end
218
- @search_range = res * 16
219
- @entry_selector = power - 1
220
- @range_shift = @table_list.length * 16 - @search_range
221
- end
222
- private :table_list_update!
223
-
224
- # Adds tbl to font. tbl is a table object
225
- # (e.g. an instance of Font::TTF::Table::Loca).
226
- def set_table(tbl)
227
- tbl_tag = tbl.tag
228
-
229
- unless tables_include? tbl_tag
230
- @table_list << tbl_tag
231
- table_list_update!
232
- end
233
- @tables[tbl_tag] = tbl
234
- end
235
-
236
- # Removes tbl from font. tbl may be a Symbol (e.g. :loca for the loca table)
237
- # or a table object (e.g. an instance of Font::TTF::Table::Loca).
238
- def unset_table(tbl)
239
- if tbl.kind_of? Symbol
240
- tbl_tag = tbl
241
- else
242
- tbl_tag = tbl.tag
243
- end
244
-
245
- @table_list.delete(tbl_tag)
246
- @tables.delete(tbl_tag)
247
- table_list_update!
248
- end
249
-
250
- # Dumps the whole font in binary raw format as found in a font file.
251
- def dump
252
- raw = ""
253
- raw += (@version || 0).to_fixed
254
- raw += (@table_list || []).length.to_ushort
255
- raw += (@search_range || 0).to_ushort
256
- raw += (@entry_selector || 0).to_ushort
257
- raw += (@range_shift || 0).to_ushort
258
-
259
-
260
- offs = IO::SIZEOF_FIXED + 4 * IO::SIZEOF_USHORT + \
261
- @table_list.length * DIR_ENTRY_SIZE
262
-
263
- dumps = []
264
- @table_list.each do |tbl_tag|
265
- tbl = get_table(tbl_tag)
266
- tag = tbl_tag.to_s
267
- tag.four_chars!
268
- raw += tag
269
- # FIXME: FontChunk#checksum method is buggy
270
- # For now, I set it to 0
271
- raw += 0.to_ulong
272
- raw += offs.to_ulong
273
- dump = tbl.dump
274
- dumps << dump
275
- len = dump.length
276
- raw += len.to_ulong
277
- offs += len
278
- end
279
-
280
- dumps.each do |dump|
281
- raw += dump
282
- end
283
-
284
- raw
285
- end
286
-
287
- end
288
-
289
- end
290
- end
@@ -1,77 +0,0 @@
1
- # TTF/Ruby, a library to read and write TrueType fonts in Ruby.
2
- # Copyright (C) 2006 Mathieu Blondel
3
- #
4
- # This program is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- module Font
19
- module TTF
20
-
21
- # A FontChunk is a portion of font. It starts at an offset and has a given
22
- # length. It is useful to handle tables that have not been implemented
23
- # or to quickly get a dump for a table that has not been modified.
24
- class FontChunk
25
-
26
- attr_reader :font
27
- attr_accessor :offset, :len
28
-
29
- def initialize(font, offset=nil, len=nil)
30
- @font = font
31
- # When a FontChunk is modified by user,
32
- # offset and len are not true anymore
33
- @offset = offset
34
- @len = len
35
- end
36
-
37
- # Returns the end of the class name as a Symbol.
38
- # Will be useful for tables, which are subclasses of FontChunk.
39
- # For example, calling tag on Font::TTF:Table::Loca object will return
40
- # :loca.
41
- def tag
42
- t = self.class.name.split("::").last.downcase.to_sym
43
- t = :"OS/2" if t == :os2
44
- t
45
- end
46
-
47
- # Basically each table is a FontChunk and tables may be created by hand
48
- # (i.e. not exist in file yet). This method returns whether the FontChunk
49
- # already exists in file or not.
50
- def exists_in_file?
51
- not @offset.nil?
52
- end
53
-
54
- # Returns raw binary data of the FontChunk.
55
- def dump
56
- @font.at_offset(@offset) do
57
- @font.read(@len)
58
- end
59
- end
60
-
61
- # Returns a checksum of dump.
62
- def self.checksum(dump)
63
- # FIXME: this methods seems to be buggy
64
- len = ((raw.length + 3) & ~3) / IO::SIZEOF_ULONG
65
- sum = 0
66
- (len - 1).times do |i|
67
- ulong_str = raw.slice(i * IO::SIZEOF_ULONG, IO::SIZEOF_ULONG)
68
- ulong = ulong_str.unpack("N")[0]
69
- sum += ulong
70
- end
71
- sum
72
- end
73
-
74
- end
75
-
76
- end
77
- end
@@ -1,408 +0,0 @@
1
- # TTF/Ruby, a library to read and write TrueType fonts in Ruby.
2
- # Copyright (C) 2006 Mathieu Blondel
3
- #
4
- # This program is free software; you can redistribute it and/or modify
5
- # it under the terms of the GNU General Public License as published by
6
- # the Free Software Foundation; either version 2 of the License, or
7
- # (at your option) any later version.
8
- #
9
- # This program is distributed in the hope that it will be useful,
10
- # but WITHOUT ANY WARRANTY; without even the implied warranty of
11
- # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12
- # GNU General Public License for more details.
13
- #
14
- # You should have received a copy of the GNU General Public License
15
- # along with this program; if not, write to the Free Software
16
- # Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
17
-
18
- module Font
19
- module TTF
20
- module Table
21
-
22
- # Cmap is the character to glyph index mapping table.
23
- class Cmap < Font::TTF::FontChunk
24
-
25
- # Base class for encoding table classes. It provides attributes which are
26
- # common to those classes such as platform_id and encoding_id.
27
- class EncodingTable < Font::TTF::FontChunk
28
-
29
- attr_accessor :table, :platform_id, :encoding_id, :offset_from_table
30
-
31
- def initialize(table, offset=nil, len=nil, platform_id=nil,
32
- encoding_id=nil)
33
- @table = table
34
- @font = table.font
35
-
36
- if not offset.nil?
37
- @offset_from_table = offset
38
- @platform_id = platform_id
39
- @encoding_id = encoding_id
40
- super(@table.font, @table.offset + offset, len)
41
- else
42
- super(@table.font)
43
- end
44
- end
45
-
46
- def unicode?
47
- @platform_id == Font::TTF::Encodings::Platform::UNICODE or \
48
- (@platform_id == Font::TTF::Encodings::Platform::MICROSOFT and \
49
- @encoding_id == Font::TTF::Encodings::MicrosoftEncoding::UNICODE)
50
- end
51
-
52
- # Returns the format (a Fixnum) of the encoding table.
53
- def format
54
- if self.class.superclass == EncodingTable
55
- self.class.name.split(//).last.to_i
56
- else
57
- nil # Not implemented table format
58
- end
59
- end
60
-
61
- end
62
-
63
- # Encoding table in format 0, the Apple standard character to glyph
64
- # mapping table.
65
- class EncodingTable0 < EncodingTable
66
-
67
- attr_accessor :version
68
- # An array of 256 elements with simple one to one mapping of
69
- # character codes to glyph indices.
70
- #
71
- # Char 0 => Index glyph_id_array[0]
72
- # Char 1 => Index glyph_id_array[1]
73
- # ...
74
- attr_accessor :glyph_id_array
75
-
76
- def initialize(*args)
77
- super(*args)
78
- if exists_in_file?
79
- # 2 * IO::SIZEOF_USHORT corresponds to format and len
80
- # that we want to skip
81
- @table.font.at_offset(@offset + 2 * IO::SIZEOF_USHORT) do
82
- @version = @font.read_ushort
83
- @glyph_id_array = @font.read_bytes(256)
84
- end
85
- else
86
- # This is to ensure that it will be an array
87
- @glyph_id_array = []
88
- end
89
- end
90
-
91
- # Dumps the table in binary raw format as may be found in a font
92
- # file.
93
- def dump
94
- raw = (format || 0).to_ushort
95
- len = 3 * IO::SIZEOF_USHORT + 256
96
- raw += len.to_ushort
97
- raw += (@version || 0).to_ushort
98
- raw += @glyph_id_array.to_bytes
99
- end
100
- end
101
-
102
- # Encoding table in format 2. Not implemented.
103
- class EncodingTable2 < EncodingTable
104
- end
105
-
106
- # Encoding table in format 4. This format is well-suited to map
107
- # several contiguous ranges, possibly with holes of characters.
108
- class EncodingTable4 < EncodingTable
109
-
110
- attr_accessor :version
111
-
112
- attr_reader :search_range, :entry_selector, :range_shift,
113
- :end_count_array, :reserved_pad, :start_count_array,
114
- :id_delta_array, :id_range_offset_array,
115
- :glyph_index_array, :segments
116
-
117
- def initialize(*args)
118
- super(*args)
119
-
120
- if exists_in_file?
121
- # 2 * IO::SIZEOF_USHORT corresponds to format and len
122
- # that we want to skip
123
- @table.font.at_offset(@offset + 2 * IO::SIZEOF_USHORT) do
124
- @version = @font.read_ushort
125
- @seg_count_x2 = @font.read_ushort
126
- @seg_count = @seg_count_x2 / 2
127
- @search_range = @font.read_ushort
128
- @entry_selector = @font.read_ushort
129
- @range_shift = @font.read_ushort
130
- @end_count_array = @font.read_ushorts(@seg_count)
131
- @reserved_pad = @font.read_ushort
132
- @start_count_array = @font.read_ushorts(@seg_count)
133
- @id_delta_array = @font.read_ushorts(@seg_count)
134
- @id_range_offset_array = @font.read_ushorts(@seg_count)
135
-
136
- @nb_glyph_indices = len - 8 * IO::SIZEOF_USHORT \
137
- - 4 * @seg_count * IO::SIZEOF_USHORT
138
- @nb_glyph_indices /= IO::SIZEOF_USHORT;
139
-
140
- if @nb_glyph_indices > 0
141
- @glyph_index_array = \
142
- @font.read_ushorts(@nb_glyph_indices)
143
- else
144
- @glyph_index_array = []
145
- end
146
-
147
- # Keep them in memory so we don't need to
148
- # recalculate them every time
149
- @segments = get_segments
150
- end # end at_offset
151
- else
152
- @segments = []
153
- @glyph_index_array = []
154
- end
155
- end # end initialize
156
-
157
- def get_segments
158
- segments = []
159
-
160
- # For each segment...
161
- @start_count_array.each_with_index do |start, curr_seg|
162
- endd = @end_count_array[curr_seg]
163
- delta = @id_delta_array[curr_seg]
164
- range = @id_range_offset_array[curr_seg]
165
-
166
- segments[curr_seg] = {}
167
-
168
- start.upto(endd) do |curr_char|
169
- if range == 0
170
- index = (curr_char + delta)
171
- else
172
- gindex = range / 2 + (curr_char - start) - \
173
- (@seg_count - curr_seg)
174
- index = @glyph_index_array[gindex]
175
- index = 0 if index.nil?
176
- index += delta if index != 0
177
- end
178
- index = index % 65536
179
- # charcode => glyph index
180
- segments[curr_seg][curr_char] = index
181
- end
182
- end
183
- segments
184
- end
185
- private :get_segments
186
-
187
- # Returns a Hash. Its keys are characters codes and associated values
188
- # are glyph indices.
189
- def charmaps
190
- hsh = {}
191
- segments.each do |seg|
192
- seg.each do |char_code, glyph_index|
193
- hsh[char_code] = glyph_index
194
- end
195
- end
196
- hsh
197
- end
198
-
199
- # Sets the charmaps. cmps is a Hash in the same fashion as the one
200
- # returned by charmaps.
201
- def charmaps=(cmps)
202
- # TODO: we would need fewer segments if we ensured that
203
- # glyphs with id in ascending order were associated
204
- # with char codes in ascending order
205
- raise "Charmaps is an empty array" if cmps.length == 0
206
-
207
- # Order is important since we will rebuild segments
208
- char_codes = cmps.keys.sort
209
-
210
- @start_count_array = []
211
- @end_count_array = []
212
- @id_delta_array = []
213
- curr_seg = 0
214
- i = 0
215
-
216
- @start_count_array[0] = char_codes.first
217
- @id_delta_array[0] = cmps[char_codes.first] - char_codes.first
218
-
219
- last_char = 0
220
- char_codes.each do |char_code|
221
- glyph_id = cmps[char_code]
222
- curr_delta = glyph_id - char_code
223
- if i > 0 and curr_delta != @id_delta_array.last
224
- # Need to create a new segment
225
- @end_count_array[curr_seg] = last_char
226
- curr_seg += 1
227
- @start_count_array[curr_seg] = char_code
228
- @id_delta_array[curr_seg] = curr_delta
229
- end
230
- last_char = char_code
231
- i += 1
232
- end
233
- seg_count = @start_count_array.length
234
- @end_count_array[seg_count - 1] = last_char
235
- @id_range_offset_array = [0] * seg_count # Range offsets not used
236
- @segments = get_segments # Recalculate segments
237
-
238
- # Values below are calculated
239
- # to allow faster computation by font rasterizers
240
- res = 1
241
- power = 0
242
- while res <= seg_count
243
- res *= 2
244
- power += 1
245
- end
246
- @search_range = res
247
- @entry_selector = power - 1
248
- @range_shift = 2 * seg_count - @search_range
249
- end
250
-
251
- # Returns index/id of glyph associated with unicode.
252
- def get_glyph_id_for_unicode(unicode)
253
- id = 0
254
- @segments.length.times do |i|
255
- if @start_count_array[i] <= unicode and \
256
- unicode <= @end_count_array[i]
257
- @segments[i].each do |char_code, glyph_id|
258
- if char_code == unicode
259
- id = glyph_id
260
- break
261
- end
262
- end
263
- end
264
- end
265
- id
266
- end
267
-
268
- # Returns the Font::TTF::Table::Glyf::SimpleGlyph or
269
- # Font::TTF::Table::Glyf::CompositeGlyph associated with unicode.
270
- def get_glyph_for_unicode(unicode)
271
- id = get_glyph_id_for_unicode(unicode)
272
- offs = @font.get_table(:loca).glyph_offsets[id]
273
- @font.get_table(:glyf).get_glyph_at_offset(offs)
274
- end
275
-
276
- # Returns the unicode of glyph with index id.
277
- def get_unicode_for_glyph_id(id)
278
- # TODO: this method could be rewritten much more efficiently
279
- # by using @start_count_array and @end_count_array
280
- unicode = 0
281
- charmaps.each do |char_code, glyph_index|
282
- if glyph_index == id
283
- unicode = char_code
284
- break
285
- end
286
- end
287
- unicode
288
- end
289
-
290
- # Dumps the table in binary raw format as may be found in a font
291
- # file.
292
- def dump
293
- raw = (format || 0).to_ushort
294
- seg_count = @segments.length || 0
295
- len = 8 * IO::SIZEOF_USHORT + 4 * seg_count * IO::SIZEOF_USHORT + \
296
- @glyph_index_array.length * IO::SIZEOF_USHORT
297
- raw += len.to_ushort
298
- raw += (@version || 0).to_ushort
299
- raw += (seg_count * 2).to_ushort
300
- raw += (@search_range || 0).to_ushort
301
- raw += (@entry_selector || 0).to_ushort
302
- raw += (@range_shift || 0).to_ushort
303
- raw += (@end_count_array || []).to_ushorts
304
- raw += (@reserved_pad || 0).to_ushort
305
- raw += (@start_count_array || []).to_ushorts
306
- raw += (@id_delta_array || []).to_ushorts
307
- raw += (@id_range_offset_array || []).to_ushorts
308
- raw += (@glyph_index_array || []).to_ushorts
309
- end
310
- end
311
-
312
- # Encoding table in format 6. Not implemented.
313
- class EncodingTable6 < EncodingTable
314
- end
315
-
316
- # Encoding table in format 8. Not implemented.
317
- class EncodingTable8 < EncodingTable
318
- end
319
-
320
- # Encoding table in format 10. Not implemented.
321
- class EncodingTable10 < EncodingTable
322
- end
323
-
324
- # Encoding table in format 12. Not implemented.
325
- class EncodingTable12 < EncodingTable
326
- end
327
-
328
- attr_accessor :version
329
- # An Array of encoding_tables. You may add or remove encoding tables
330
- # from this array.
331
- attr_accessor :encoding_tables
332
-
333
- def initialize(*args)
334
- super(*args)
335
-
336
- if exists_in_file?
337
- @font.at_offset(@offset) do
338
- @version = @font.read_ushort
339
- @encoding_table_num = @font.read_ushort
340
- @encoding_tables = []
341
- @encoding_table_num.times do
342
- platform_id = @font.read_ushort
343
- encoding_id = @font.read_ushort
344
- offset = @font.read_ulong
345
-
346
- @font.at_offset(@offset + offset) do
347
- format = @font.read_ushort
348
- len = @font.read_ushort
349
-
350
- if [0, 2, 4, 6, 8, 10, 12].include? format
351
- klass = eval("EncodingTable%d" % format)
352
- else
353
- klass = EncodingTable
354
- end
355
-
356
- @encoding_tables << klass.new(self,
357
- offset,
358
- len,
359
- platform_id,
360
- encoding_id)
361
- end
362
- end
363
-
364
- end
365
- else
366
- @encoding_tables = []
367
- end
368
- end
369
-
370
- # Returns a new empty EncodingTable0 object that you may add to the
371
- # encoding_tables array.
372
- def get_new_encoding_table0
373
- EncodingTable0.new(self)
374
- end
375
-
376
- # Returns a new empty EncodingTable4 object that you may add to the
377
- # encoding_tables array.
378
- def get_new_encoding_table4
379
- EncodingTable4.new(self)
380
- end
381
-
382
- # Dumps the cmap table in binary raw format as may be found in a font
383
- # file.
384
- def dump
385
- raw = (@version || 0).to_ushort
386
- raw += (@encoding_tables.length || 0).to_ushort
387
- dumps = []
388
- offs = 2 * IO::SIZEOF_USHORT + @encoding_tables.length * \
389
- (2 * IO::SIZEOF_USHORT + IO::SIZEOF_ULONG)
390
- @encoding_tables.each do |enc_tbl|
391
- raw += (enc_tbl.platform_id || 3).to_ushort
392
- raw += (enc_tbl.encoding_id || 1).to_ushort
393
- dump = enc_tbl.dump
394
- dumps << dump
395
- raw += offs.to_ulong
396
- offs += dump.length
397
- end
398
- dumps.each do |dump|
399
- raw += dump
400
- end
401
- raw
402
- end
403
-
404
- end
405
-
406
- end
407
- end
408
- end