prawn 0.2.3 → 0.3.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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