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,49 +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
- # Cvt is the Control Value table. It references values that can be
23
- # referenced by instructions (used for hinting, aka grid-fitting).
24
- class Cvt < Font::TTF::FontChunk
25
-
26
- attr_accessor :instructions
27
-
28
- def initialize(*args)
29
- super(*args)
30
-
31
- if exists_in_file?
32
- @font.at_offset(@offset) do
33
- n = @len / IO::SIZEOF_FWORD
34
- @instructions = @font.read_fwords(n)
35
- end
36
- end
37
- end
38
-
39
- # Dumps the cvt table in binary raw format as may be found in a font
40
- # file.
41
- def dump
42
- (@instructions || []).to_fwords
43
- end
44
-
45
- end
46
-
47
- end
48
- end
49
- end
@@ -1,48 +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
- # Fpgm is the Font Program table. It is similar to the Cvt table except
23
- # it is only run once, when the font is first used.
24
- class Fpgm < Font::TTF::FontChunk
25
-
26
- attr_accessor :instructions
27
-
28
- def initialize(*args)
29
- super(*args)
30
-
31
- if exists_in_file?
32
- @font.at_offset(@offset) do
33
- @instructions = @font.read_bytes(@len)
34
- end
35
- end
36
- end
37
-
38
- # Dumps the fpgm table in binary raw format as may be found in a font
39
- # file.
40
- def dump
41
- (@instructions || []).to_bytes
42
- end
43
-
44
- end
45
-
46
- end
47
- end
48
- end
@@ -1,88 +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
- # Gasp is the Grid-fitting and scan conversion procedure table.
23
- class Gasp < Font::TTF::FontChunk
24
-
25
- class GaspRange < Font::TTF::FontChunk
26
-
27
- SIZEOF_GASP_RANGE = 2 * IO::SIZEOF_USHORT
28
-
29
- attr_accessor :range_max_ppem, :range_gasp_behavior
30
-
31
- def initialize(table, n=nil)
32
- if n.nil?
33
- # when object is created by hand
34
- super(table.font)
35
- else
36
- offs = table.offset + 2 * IO::SIZEOF_USHORT + \
37
- n * SIZEOF_GASP_RANGE
38
- super(table.font, offs, SIZEOF_GASP_RANGE)
39
-
40
- table.font.at_offset(@offset) do
41
- @range_max_ppem = table.font.read_ushort
42
- @range_gasp_behavior = table.font.read_ushort
43
- end
44
- end
45
- end
46
-
47
- def dump
48
- raw = (@range_max_ppem || 0).to_ushort
49
- raw += (@range_gasp_behavior || 0).to_ushort
50
- end
51
-
52
- end
53
-
54
- attr_accessor :version
55
- # An Array of GaspRange objects.
56
- attr_accessor :gasp_ranges
57
-
58
- def initialize(*args)
59
- super(*args)
60
-
61
- if exists_in_file?
62
- @font.at_offset(@offset) do
63
- @version = @font.read_ushort
64
- @num_ranges = @font.read_ushort
65
- @gasp_ranges = []
66
- @num_ranges.times do |i|
67
- @gasp_ranges << GaspRange.new(self, i)
68
- end
69
- end
70
- end
71
- end
72
-
73
- # Dumps the gasp table in binary raw format as may be found in a font
74
- # file.
75
- def dump
76
- raw = (@version || 0).to_ushort
77
- raw += (@gasp_ranges || []).length.to_ushort
78
- @gasp_ranges.each do |gr|
79
- raw += gr.dump
80
- end
81
- raw
82
- end
83
-
84
- end
85
-
86
- end
87
- end
88
- end
@@ -1,452 +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
- # Glyf is the Glyph data table.
23
- class Glyf < Font::TTF::FontChunk
24
-
25
- # Base class for SimpleGlyph and CompositeGlyph.
26
- class Glyph < Font::TTF::FontChunk
27
-
28
- attr_accessor :num_contours, :x_min, :y_min, :x_max, :y_max
29
-
30
- def initialize(table, offset=nil)
31
- @table = table
32
- @offset_from_table = offset
33
- super(@table.font, @table.offset + @offset_from_table)
34
-
35
- if exists_in_file?
36
- @font.at_offset(@offset) do
37
- @num_contours = @font.read_short
38
- @x_min = @font.read_fword
39
- @y_min = @font.read_fword
40
- @x_max = @font.read_fword
41
- @y_max = @font.read_fword
42
- end
43
- end
44
- end
45
-
46
- def dump
47
- raw = (@num_contours || 0).to_short
48
- raw += (@x_min || 0).to_fword
49
- raw += (@y_min || 0).to_fword
50
- raw += (@x_max || 0).to_fword
51
- raw += (@y_max || 0).to_fword
52
- end
53
-
54
- # Returns whether the glyph is composite or not.
55
- def composite?
56
- self.class == CompositeGlyph
57
- end
58
-
59
- # Returns whether is simple (i.e. not composite) or not.
60
- def simple?
61
- self.class == SimpleGlyph
62
- end
63
-
64
- end
65
-
66
- # SimpleGlyph class.
67
- class SimpleGlyph < Glyph
68
-
69
- Point = Struct.new(:rel_x, :abs_x, :rel_y, :abs_y,
70
- :end_of_contour, :on_curve)
71
-
72
- # Point is helper class which gives information on a point
73
- # such as it absolute (abs_x, abs_y) and relative (rel_x, rel_y)
74
- # coordinates
75
- class Point
76
- # Whether the point is end of contour or not.
77
- alias :end_of_contour? :end_of_contour
78
- # Whether the point is on curve or not.
79
- alias :on_curve? :on_curve
80
-
81
- # Whether the point is off curve or not.
82
- def off_curve?
83
- not on_curve?
84
- end
85
- end
86
-
87
- FLAG_ON_CURVE = 0b1
88
- FLAG_X_SHORT_VECTOR = 0b10
89
- FLAG_Y_SHORT_VECTOR = 0b100
90
- FLAG_REPEAT = 0b1000
91
- FLAG_X_IS_SAME = 0b10000
92
- FLAG_Y_IS_SAME = 0b100000
93
-
94
- attr_accessor :end_pts_of_contours, :instructions, :flags,
95
- :x_coordinates, :y_coordinates
96
-
97
- def initialize(*args)
98
- super(*args)
99
-
100
- if exists_in_file?
101
- offs = @offset + IO::SIZEOF_SHORT + 4 * IO::SIZEOF_FWORD
102
- @font.at_offset(offs) do
103
- @end_pts_of_contours = @font.read_ushorts(@num_contours)
104
- instruction_len = @font.read_ushort
105
- @instructions = @font.read_bytes(instruction_len)
106
- unless @end_pts_of_contours.empty?
107
- num_points = @end_pts_of_contours.last + 1
108
- else
109
- num_points = 0
110
- end
111
- @flags = []
112
- while @flags.length < num_points
113
- flag = @font.read_byte
114
- @flags << flag
115
- if flag & FLAG_REPEAT != 0
116
- @font.read_byte.times do
117
- @flags << flag
118
- end
119
- end
120
- end
121
- @x_coordinates = []
122
- @y_coordinates = []
123
- [[@x_coordinates, FLAG_X_SHORT_VECTOR, FLAG_X_IS_SAME],
124
- [@y_coordinates, FLAG_Y_SHORT_VECTOR, FLAG_Y_IS_SAME]
125
- ].each do |coordinates, short, same|
126
- num_points.times do |i|
127
- flag = @flags[i]
128
- if flag & short != 0
129
- # if the coordinate is a BYTE
130
- if flag & same != 0
131
- coordinates << @font.read_byte
132
- else
133
- coordinates << -@font.read_byte
134
- end
135
- else
136
- # the coordinate is a SHORT
137
- if flag & same != 0
138
- # same so 0 (relative coordinates)
139
- coordinates << 0
140
- else
141
- coordinates << @font.read_short
142
- end
143
- end
144
- end
145
- end
146
- @len = @font.pos - @offset
147
- end
148
- end
149
-
150
- end
151
-
152
- # Returns an Array of [x,y] pairs of relative coordinates.
153
- def rel_coordinates
154
- coords = []
155
- @x_coordinates.length.times do |i|
156
- coords << [@x_coordinates[i], @y_coordinates[i]]
157
- end
158
- coords
159
- end
160
-
161
- # Returns an Array of [x,y] pairs of absolute coordinates.
162
- def abs_coordinates
163
- abs_x = 0
164
- abs_y = 0
165
- coords = []
166
- rel_coordinates.each do |rel_x, rel_y|
167
- abs_x += rel_x
168
- abs_y += rel_y
169
- coords << [abs_x, abs_y]
170
- end
171
- coords
172
- end
173
-
174
- # Returns an Array of Point objects.
175
- def points
176
- x_abs = 0
177
- y_abs = 0
178
- pnts = []
179
- @x_coordinates.length.times do |i|
180
- pnt = Point.new
181
- pnt.rel_x = @x_coordinates[i]
182
- pnt.rel_y = @y_coordinates[i]
183
- x_abs += pnt.rel_x
184
- y_abs += pnt.rel_y
185
- pnt.abs_x = x_abs
186
- pnt.abs_y = y_abs
187
- pnt.end_of_contour = @end_pts_of_contours.include? i
188
- pnt.on_curve = (@flags[i] & FLAG_ON_CURVE != 0)
189
- pnts << pnt
190
- end
191
- pnts
192
- end
193
-
194
- def dump
195
- raw = super
196
- raw += @end_pts_of_contours.to_ushorts
197
- raw += @instructions.length.to_ushort
198
- raw += @instructions.to_bytes
199
-
200
- tmp = ""
201
- [[@x_coordinates, FLAG_X_SHORT_VECTOR, FLAG_X_IS_SAME],
202
- [@y_coordinates, FLAG_Y_SHORT_VECTOR, FLAG_Y_IS_SAME]
203
- ].each do |coordinates, short, same|
204
- coordinates.each_with_index do |coord, i|
205
- if 0 <= coord and coord <= 255
206
- @flags[i] = (@flags[i] | short) | same
207
- tmp += coord.to_byte
208
- elsif -255 <= coord and coord < 0
209
- @flags[i] = (@flags[i] | short) & ~same
210
- tmp += (-coord).to_byte
211
- elsif coord == 0
212
- @flags[i] = (@flags[i] & ~short) | same
213
- else
214
- @flags[i] = (@flags[i] & ~short) & ~same
215
- tmp += coord.to_short
216
- end
217
- end
218
- end
219
-
220
- # We write all flags rather than using the flag_repeat trick
221
- # So we unset the "repeat" bit for all flags
222
- # TODO: implement the repeat feature (this saves space)
223
- raw += @flags.collect { |f| f & ~FLAG_REPEAT }.to_bytes
224
-
225
- raw += tmp
226
- end
227
- end
228
-
229
- # CompositeGlyph class.
230
- class CompositeGlyph < Glyph
231
-
232
- GlyphComponent = Struct.new(:flags, :index, :args, :scale,
233
- :xscale, :yscale, :scale01, :scale10)
234
-
235
- ARG_1_AND_2_ARE_WORDS = 0b1
236
- ARGS_ARE_XY_VALUES = 0b10
237
- ROUND_XY_TO_GRID = 0b100
238
- WE_HAVE_A_SCALE = 0b1000
239
- RESERVED = 0b10000
240
- MORE_COMPONENTS = 0b100000
241
- WE_HAVE_AN_X_AND_Y_SCALE = 0b1000000
242
- WE_HAVE_A_TWO_BY_TWO = 0b10000000
243
- WE_HAVE_INSTRUCTIONS = 0b100000000
244
- USE_MY_METRICS = 0b1000000000
245
-
246
- # An Array of GlyphComponent objects
247
- attr_accessor :components
248
- # An Array of instructions (Fixnums)
249
- attr_accessor :instructions
250
-
251
- def initialize(*args)
252
- super(*args)
253
-
254
- if exists_in_file?
255
- offs = @offset + IO::SIZEOF_SHORT + 4 * IO::SIZEOF_FWORD
256
- @font.at_offset(offs) do
257
- @components = []
258
- continue = true
259
- while continue
260
- gc = GlyphComponent.new
261
- gc.flags = @font.read_ushort
262
- gc.index = @font.read_ushort
263
-
264
- gc.args = []
265
- if gc.flags & ARG_1_AND_2_ARE_WORDS != 0
266
- gc.args[0] = @font.read_short
267
- gc.args[1] = @font.read_short
268
- else
269
- gc.args[0] = @font.read_ushort
270
- end
271
-
272
- if gc.flags & WE_HAVE_A_SCALE != 0
273
- gc.scale = @font.read_f2dot14
274
- elsif gc.flags & WE_HAVE_AN_X_AND_Y_SCALE != 0
275
- gc.xscale = @font.read_f2dot14
276
- gc.yscale = @font.read_f2dot14
277
- elsif gc.flags & WE_HAVE_A_TWO_BY_TWO != 0
278
- gc.xscale = @font.read_f2dot14
279
- gc.scale01 = @font.read_f2dot14
280
- gc.scale10 = @font.read_f2dot14
281
- gc.yscale = @font.read_f2dot14
282
- end
283
- @components << gc
284
- continue = (gc.flags & MORE_COMPONENTS != 0)
285
- end
286
-
287
- if @components.last.flags & \
288
- WE_HAVE_INSTRUCTIONS != 0
289
- inst_len = @font.read_ushort
290
- @instructions = @font.read_bytes(inst_len)
291
- else
292
- @instructions = []
293
- end
294
-
295
- @len = @font.pos - @offset
296
- end
297
- end
298
- end
299
-
300
- def dump
301
- raw = super
302
- components_len = @components.length
303
- @components.each_with_index do |gc, i|
304
- flags = gc.flags
305
- tmp = ""
306
- if not gc.args.nil? and gc.args.length == 2
307
- flags |= ARG_1_AND_2_ARE_WORDS
308
- tmp += gc.args[0].to_short
309
- tmp += gc.args[1].to_short
310
- else
311
- flags &= ~ARG_1_AND_2_ARE_WORDS
312
- tmp += gc.args[0].to_ushort
313
- end
314
- if not gc.scale.nil?
315
- flags |= WE_HAVE_A_SCALE
316
- tmp += gc.scale.to_f2dot14
317
- elsif not gc.scale01.nil?
318
- flags |= WE_HAVE_A_TWO_BY_TWO
319
- tmp += gc.xscale.to_f2dot14
320
- tmp += gc.scale01.to_f2dot14
321
- tmp += gc.scale10.to_f2dot14
322
- tmp += gc.yscale.to_f2dot14
323
- elsif not gc.xscale.nil?
324
- flags |= WE_HAVE_AN_X_AND_Y_SCALE
325
- tmp += gc.xscale.to_f2dot14
326
- tmp += gc.yscale.to_f2dot14
327
- end
328
-
329
- if i < components_len - 1
330
- flags |= MORE_COMPONENTS
331
- else
332
- flags &= ~MORE_COMPONENTS
333
- if @instructions.length > 0
334
- flags |= WE_HAVE_INSTRUCTIONS
335
- else
336
- flags &= ~WE_HAVE_INSTRUCTIONS
337
- end
338
- end
339
- raw += flags.to_ushort
340
- raw += gc.index.to_ushort
341
- raw += tmp
342
- end
343
- unless @instructions.empty?
344
- raw += @instructions.length.to_ushort
345
- raw += @instructions.to_bytes
346
- end
347
- raw
348
- end
349
- end
350
-
351
- attr_accessor :glyphs
352
-
353
- def initialize(*args)
354
- super(*args)
355
- end
356
-
357
- # Returns the kind of glyph at offset, i.e. either SimpleGlyph
358
- # or CompositeGlyph.
359
- def kind_of_glyph_at_offset(offs_from_table)
360
- @font.at_offset(@offset + offs_from_table) do
361
- num_contours = @font.read_short
362
- if num_contours >= 0
363
- SimpleGlyph
364
- else
365
- CompositeGlyph
366
- end
367
- end
368
- end
369
-
370
- def get_glyph_at_offset(offs_from_table)
371
- klass = kind_of_glyph_at_offset(offs_from_table)
372
- klass.new(self, offs_from_table)
373
- end
374
-
375
- def get_glyphs
376
- loca = @font.get_table(:loca)
377
- glyphs = []
378
- loca.glyph_offsets[0...-1].each do |off|
379
- glyphs << get_glyph_at_offset(off)
380
- end
381
- glyphs
382
- end
383
- private :get_glyphs
384
-
385
- # Returns all Glyph (SimpleGlyph or CompositeGlyph) in an Array.
386
- # This method may be real overkill if you just need to access a few glyphs.
387
- # In this case, you should use the loca table (Font::TTF::Table::Loca)
388
- # to get offsets and get_glyph_at_offset to get glyph associated with them.
389
- def glyphs
390
- @glyphs ||= get_glyphs
391
- end
392
-
393
- # Sets glyphs. new_glyphs is an Array of Glyph objects.
394
- def glyphs=(new_glyphs)
395
- @glyphs = new_glyphs
396
- @font.get_table(:maxp).num_glyphs = @glyphs.length
397
- @font.get_table(:post).num_glyphs = @glyphs.length
398
- end
399
-
400
- # Iterates over each glyph.
401
- # It does not load all glyphs like glyphs.each would do.
402
- def each_glyph
403
- loca = @font.get_table(:loca)
404
- glyphs = []
405
- loca.glyph_offsets[0...-1].each do |off|
406
- glyph = get_glyph_at_offset(off)
407
- yield glyph
408
- end
409
- end
410
-
411
- # Dumps the glyf table in binary raw format as may be found in a font
412
- # file.
413
- def dump
414
- raw = ""
415
- offs = 0
416
- glyph_offsets = []
417
- glyphs.each do |glyph|
418
- glyph_offsets << offs
419
- dump = glyph.dump
420
- len = dump.length
421
- raw += dump
422
- # offsets should be multiples of SIZEOF_ULONG
423
- diff = len % IO::SIZEOF_ULONG
424
- raw += " " * diff
425
- offs += len + diff
426
- end
427
- # An additional offset is added so that the length of the last
428
- # glyph can be calculated:
429
- # len of last glyph = additional offs - last glyph offs
430
- glyph_offsets << offs
431
-
432
- # 2 ** 16 * 2 = 131072 is the maximum size supported
433
- # if the short format is used in the loca table
434
- # Using shorts saves two bytes per glyph!
435
- if offs < 131072
436
- @font.get_table(:head).index_to_loc_format = \
437
- Font::TTF::Table::Head::SHORT_FORMAT
438
- else
439
- @font.get_table(:head).index_to_loc_format = \
440
- Font::TTF::Table::Head::LONG_FORMAT
441
- end
442
-
443
- @font.get_table(:loca).glyph_offsets = glyph_offsets
444
-
445
- raw
446
- end
447
-
448
- end
449
-
450
- end
451
- end
452
- end