fullcirclegroup-prawn 0.2.99.3

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 (117) hide show
  1. data/COPYING +340 -0
  2. data/LICENSE +56 -0
  3. data/README +47 -0
  4. data/Rakefile +76 -0
  5. data/data/fonts/Activa.ttf +0 -0
  6. data/data/fonts/Chalkboard.ttf +0 -0
  7. data/data/fonts/Courier-Bold.afm +342 -0
  8. data/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/data/fonts/Courier-Oblique.afm +342 -0
  10. data/data/fonts/Courier.afm +342 -0
  11. data/data/fonts/DejaVuSans.ttf +0 -0
  12. data/data/fonts/Dustismo_Roman.ttf +0 -0
  13. data/data/fonts/Helvetica-Bold.afm +2827 -0
  14. data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  15. data/data/fonts/Helvetica-Oblique.afm +3051 -0
  16. data/data/fonts/Helvetica.afm +3051 -0
  17. data/data/fonts/MustRead.html +19 -0
  18. data/data/fonts/Symbol.afm +213 -0
  19. data/data/fonts/Times-Bold.afm +2588 -0
  20. data/data/fonts/Times-BoldItalic.afm +2384 -0
  21. data/data/fonts/Times-Italic.afm +2667 -0
  22. data/data/fonts/Times-Roman.afm +2419 -0
  23. data/data/fonts/ZapfDingbats.afm +225 -0
  24. data/data/fonts/comicsans.ttf +0 -0
  25. data/data/fonts/gkai00mp.ttf +0 -0
  26. data/data/images/arrow.png +0 -0
  27. data/data/images/arrow2.png +0 -0
  28. data/data/images/barcode_issue.png +0 -0
  29. data/data/images/dice.alpha +0 -0
  30. data/data/images/dice.dat +0 -0
  31. data/data/images/dice.png +0 -0
  32. data/data/images/page_white_text.alpha +0 -0
  33. data/data/images/page_white_text.dat +0 -0
  34. data/data/images/page_white_text.png +0 -0
  35. data/data/images/pigs.jpg +0 -0
  36. data/data/images/rails.dat +0 -0
  37. data/data/images/rails.png +0 -0
  38. data/data/images/ruport.png +0 -0
  39. data/data/images/ruport_data.dat +0 -0
  40. data/data/images/ruport_transparent.png +0 -0
  41. data/data/images/ruport_type0.png +0 -0
  42. data/data/images/stef.jpg +0 -0
  43. data/data/images/web-links.dat +1 -0
  44. data/data/images/web-links.png +0 -0
  45. data/data/shift_jis_text.txt +1 -0
  46. data/examples/addressbook.csv +6 -0
  47. data/examples/alignment.rb +16 -0
  48. data/examples/bounding_boxes.rb +30 -0
  49. data/examples/canvas.rb +12 -0
  50. data/examples/cell.rb +38 -0
  51. data/examples/chinese_text_wrapping.rb +17 -0
  52. data/examples/currency.csv +1834 -0
  53. data/examples/curves.rb +10 -0
  54. data/examples/family_based_styling.rb +21 -0
  55. data/examples/fancy_table.rb +61 -0
  56. data/examples/flowing_text_with_header_and_footer.rb +72 -0
  57. data/examples/font_size.rb +27 -0
  58. data/examples/hexagon.rb +14 -0
  59. data/examples/image.rb +23 -0
  60. data/examples/image2.rb +13 -0
  61. data/examples/image_flow.rb +34 -0
  62. data/examples/kerning.rb +27 -0
  63. data/examples/lazy_bounding_boxes.rb +19 -0
  64. data/examples/line.rb +31 -0
  65. data/examples/multi_page_layout.rb +14 -0
  66. data/examples/page_geometry.rb +28 -0
  67. data/examples/png_types.rb +23 -0
  68. data/examples/polygons.rb +16 -0
  69. data/examples/position_by_baseline.rb +26 -0
  70. data/examples/ruport_formatter.rb +50 -0
  71. data/examples/ruport_helpers.rb +18 -0
  72. data/examples/russian_boxes.rb +34 -0
  73. data/examples/simple_text.rb +15 -0
  74. data/examples/simple_text_ttf.rb +16 -0
  75. data/examples/sjis.rb +21 -0
  76. data/examples/span.rb +27 -0
  77. data/examples/table.rb +47 -0
  78. data/examples/table_header_color.rb +16 -0
  79. data/examples/text_flow.rb +65 -0
  80. data/examples/top_and_bottom_cells.rb +40 -0
  81. data/examples/utf8.rb +12 -0
  82. data/lib/prawn.rb +67 -0
  83. data/lib/prawn/compatibility.rb +46 -0
  84. data/lib/prawn/document.rb +309 -0
  85. data/lib/prawn/document/bounding_box.rb +362 -0
  86. data/lib/prawn/document/internals.rb +113 -0
  87. data/lib/prawn/document/page_geometry.rb +79 -0
  88. data/lib/prawn/document/span.rb +47 -0
  89. data/lib/prawn/document/table.rb +350 -0
  90. data/lib/prawn/document/text.rb +196 -0
  91. data/lib/prawn/errors.rb +48 -0
  92. data/lib/prawn/font.rb +356 -0
  93. data/lib/prawn/font/cmap.rb +59 -0
  94. data/lib/prawn/font/metrics.rb +378 -0
  95. data/lib/prawn/font/wrapping.rb +47 -0
  96. data/lib/prawn/graphics.rb +252 -0
  97. data/lib/prawn/graphics/cell.rb +264 -0
  98. data/lib/prawn/graphics/color.rb +132 -0
  99. data/lib/prawn/images.rb +336 -0
  100. data/lib/prawn/images/jpg.rb +45 -0
  101. data/lib/prawn/images/png.rb +199 -0
  102. data/lib/prawn/pdf_object.rb +73 -0
  103. data/lib/prawn/reference.rb +56 -0
  104. data/spec/bounding_box_spec.rb +141 -0
  105. data/spec/document_spec.rb +181 -0
  106. data/spec/font_spec.rb +141 -0
  107. data/spec/graphics_spec.rb +209 -0
  108. data/spec/images_spec.rb +68 -0
  109. data/spec/jpg_spec.rb +25 -0
  110. data/spec/metrics_spec.rb +62 -0
  111. data/spec/pdf_object_spec.rb +112 -0
  112. data/spec/png_spec.rb +196 -0
  113. data/spec/reference_spec.rb +42 -0
  114. data/spec/spec_helper.rb +23 -0
  115. data/spec/table_spec.rb +179 -0
  116. data/spec/text_spec.rb +135 -0
  117. metadata +181 -0
@@ -0,0 +1,196 @@
1
+ # encoding: utf-8
2
+
3
+ # text.rb : Implements PDF text primitives
4
+ #
5
+ # Copyright May 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+ require "zlib"
9
+ require "prawn/document/text/box"
10
+
11
+ module Prawn
12
+ class Document
13
+ module Text
14
+ # Draws text on the page. If a point is specified via the +:at+
15
+ # option the text will begin exactly at that point, and the string is
16
+ # assumed to be pre-formatted to properly fit the page.
17
+ #
18
+ # pdf.text "Hello World", :at => [100,100]
19
+ # pdf.text "Goodbye World", :at => [50,50], :size => 16
20
+ #
21
+ # When +:at+ is not specified, Prawn attempts to wrap the text to
22
+ # fit within your current bounding box (or margin_box if no bounding box
23
+ # is being used ). Text will flow onto the next page when it reaches
24
+ # the bottom of the bounding box. Text wrap in Prawn does not re-flow
25
+ # linebreaks, so if you want fully automated text wrapping, be sure to
26
+ # remove newlines before attempting to draw your string.
27
+ #
28
+ # pdf.text "Will be wrapped when it hits the edge of your bounding box"
29
+ # pdf.text "This will be centered", :align => :center
30
+ # pdf.text "This will be right aligned", :align => :right
31
+ #
32
+ # Wrapping is done by splitting words by spaces by default. If your text
33
+ # does not contain spaces, you can wrap based on characters instead:
34
+ #
35
+ # pdf.text "This will be wrapped by character", :wrap => :character
36
+ #
37
+ # If your font contains kerning pairs data that Prawn can parse, the
38
+ # text will be kerned by default. You can disable this feature by passing
39
+ # <tt>:kerning => false</tt>.
40
+ #
41
+ # === Text Positioning Details:
42
+ #
43
+ # FIXME: If we go with this of using ascender for TTF and font height
44
+ # For AFM, we need to document the sucker.
45
+ #
46
+ # When using the +:at+ parameter, Prawn will position your text by its
47
+ # baseline, and flow along a single line.
48
+ #
49
+ # When using automatic text flow, Prawn will position your text exactly
50
+ # font.height *below* the baseline, and space each line of text by
51
+ # font.height + options[:spacing] (default 0)
52
+ #
53
+ # Finally, the drawing position will be moved to the baseline of final
54
+ # line of text, plus any additional spacing.
55
+ #
56
+ # If you wish to position your flowing text by it's baseline rather
57
+ # than +font.height+ below, simply call <tt>move_up font.height</tt>
58
+ # before your call to text()
59
+ #
60
+ # == Rotation
61
+ #
62
+ # Text can be rotated before it is placed on the canvas by specifying the
63
+ # :rotate option. Rotation occurs counter-clockwise.
64
+ #
65
+ # == Encoding
66
+ #
67
+ # Note that strings passed to this function should be encoded as UTF-8.
68
+ # If you get unexpected characters appearing in your rendered document,
69
+ # check this.
70
+ #
71
+ # If the current font is a built-in one, although the string must be
72
+ # encoded as UTF-8, only characters that are available in WinAnsi
73
+ # are allowed.
74
+ #
75
+ # If an empty box is rendered to your PDF instead of the character you
76
+ # wanted it usually means the current font doesn't include that character.
77
+ #
78
+ def text(text,options={})
79
+ # we'll be messing with the strings encoding, don't change the users
80
+ # original string
81
+ text = text.to_s.dup
82
+
83
+ # we might also mess with the font
84
+ original_font = font.name
85
+
86
+ options = text_options.merge(options)
87
+ process_text_options(options)
88
+
89
+ font.normalize_encoding(text) unless @skip_encoding
90
+
91
+ if options[:at]
92
+ x,y = translate(options[:at])
93
+ font.size(options[:size]) { add_text_content(text,x,y,options) }
94
+ else
95
+ if options[:rotate]
96
+ raise ArgumentError, "Rotated text may only be used with :at"
97
+ end
98
+ wrapped_text(text,options)
99
+ end
100
+
101
+ font(original_font)
102
+ end
103
+
104
+ # A hash of configuration options, to be used globally by text().
105
+ #
106
+ # pdf.text_options.update(:size => 16, :align => :right)
107
+ # pdf.text "Hello World" #=> Size 16 w. right alignment
108
+ #
109
+ def text_options
110
+ @text_options ||= {}
111
+ end
112
+
113
+ private
114
+
115
+ def process_text_options(options)
116
+ Prawn.verify_options [:style, :kerning, :size, :at, :wrap,
117
+ :spacing, :align, :rotate ], options
118
+
119
+ if options[:style]
120
+ raise "Bad font family" unless font.family
121
+ font(font.family,:style => options[:style])
122
+ end
123
+
124
+ unless options.key?(:kerning)
125
+ options[:kerning] = font.metrics.has_kerning_data?
126
+ end
127
+
128
+ options[:size] ||= font.size
129
+ end
130
+
131
+ def move_text_position(dy)
132
+ bottom = @bounding_box.stretchy? ? @margin_box.absolute_bottom :
133
+ @bounding_box.absolute_bottom
134
+ start_new_page if (y - dy) < bottom
135
+
136
+ self.y -= dy
137
+ end
138
+
139
+ def wrapped_text(text,options)
140
+ options[:align] ||= :left
141
+
142
+ font.size(options[:size]) do
143
+ text = font.metrics.naive_wrap(text, bounds.right, font.size,
144
+ :kerning => options[:kerning], :mode => options[:wrap])
145
+
146
+ lines = text.lines
147
+
148
+ lines.each do |e|
149
+ if font.metrics.type0?
150
+ move_text_position(font.ascender)
151
+ else
152
+ move_text_position(font.height)
153
+ end
154
+
155
+ line_width = font.width_of(e)
156
+ case(options[:align])
157
+ when :left
158
+ x = @bounding_box.absolute_left
159
+ when :center
160
+ x = @bounding_box.absolute_left +
161
+ (@bounding_box.width - line_width) / 2.0
162
+ when :right
163
+ x = @bounding_box.absolute_right - line_width
164
+ end
165
+
166
+ add_text_content(e,x,y,options)
167
+
168
+ if font.metrics.type0?
169
+ move_text_position(font.height - font.ascender)
170
+ end
171
+
172
+ move_text_position(options[:spacing]) if options[:spacing]
173
+ end
174
+ end
175
+ end
176
+
177
+ def add_text_content(text, x, y, options)
178
+ text = font.metrics.convert_text(text,options)
179
+
180
+ add_content "\nBT"
181
+ add_content "/#{font.identifier} #{font.size} Tf"
182
+ if options[:rotate]
183
+ rad = options[:rotate].to_i * Math::PI / 180
184
+ arr = [ Math.cos(rad), Math.sin(rad), -Math.sin(rad), Math.cos(rad), x, y ]
185
+ add_content "%.3f %.3f %.3f %.3f %.3f %.3f Tm" % arr
186
+ else
187
+ add_content "#{x} #{y} Td"
188
+ end
189
+ rad = 1.570796
190
+ add_content Prawn::PdfObject(text, true) <<
191
+ " #{options[:kerning] ? 'TJ' : 'Tj'}"
192
+ add_content "ET\n"
193
+ end
194
+ end
195
+ end
196
+ end
@@ -0,0 +1,48 @@
1
+ # encoding: utf-8
2
+
3
+ # errors.rb : Implements custom error classes for Prawn
4
+ #
5
+ # Copyright April 2008, Gregory Brown. All Rights Reserved.
6
+ #
7
+ # This is free software. Please see the LICENSE and COPYING files for details.
8
+
9
+ module Prawn
10
+ module Errors
11
+
12
+ # This error is raised when Prawn::PdfObject() encounters a Ruby object it
13
+ # cannot convert to PDF
14
+ #
15
+ class FailedObjectConversion < StandardError; end
16
+
17
+ # This error is raised when Document#page_layout is set to anything
18
+ # other than :portrait or :landscape
19
+ #
20
+ class InvalidPageLayout < StandardError; end
21
+
22
+ # This error is raised when Prawn cannot find a specified font
23
+ #
24
+ class UnknownFont < StandardError; end
25
+
26
+ # This error is raised when Prawn is being used on a M17N aware VM,
27
+ # and the user attempts to add text that isn't compatible with UTF-8
28
+ # to their document
29
+ #
30
+ class IncompatibleStringEncoding < StandardError; end
31
+
32
+ # This error is raised when Prawn encounters an unknown key in functions
33
+ # that accept an options hash. This usually means there is a typo in your
34
+ # code or that the option you are trying to use has a different name than
35
+ # what you have specified.
36
+ #
37
+ class UnknownOption < StandardError; end
38
+
39
+ # This error is raised when table data is malformed
40
+ #
41
+ class InvalidTableData < StandardError; end
42
+
43
+ # This error is raised when an empty or nil table is rendered
44
+ #
45
+ class EmptyTable < StandardError; end
46
+
47
+ end
48
+ end
data/lib/prawn/font.rb ADDED
@@ -0,0 +1,356 @@
1
+ # encoding: utf-8
2
+
3
+ require "prawn/font/wrapping"
4
+ require "prawn/font/metrics"
5
+ require "prawn/font/cmap"
6
+
7
+ module Prawn
8
+
9
+ class Document
10
+ # Without arguments, this returns the currently selected font. Otherwise,
11
+ # it sets the current font.
12
+ #
13
+ # The single parameter must be a string. It can be one of the 14 built-in
14
+ # fonts supported by PDF, or the location of a TTF file. The BUILT_INS
15
+ # array specifies the valid built in font values.
16
+ #
17
+ # pdf.font "Times-Roman"
18
+ # pdf.font "Chalkboard.ttf"
19
+ #
20
+ # If a ttf font is specified, the full file will be embedded in the
21
+ # rendered PDF. This should be your preferred option in most cases.
22
+ # It will increase the size of the resulting file, but also make it
23
+ # more portable.
24
+ #
25
+ def font(name=nil, options={})
26
+ return @font || font("Helvetica") if name.nil?
27
+
28
+ if block_given?
29
+ original_name = font.name
30
+ original_size = font.size
31
+ end
32
+
33
+ @font = find_font(name, options)
34
+ @font.add_to_current_page
35
+
36
+ @font.size = options[:size] if options[:size]
37
+
38
+ if block_given?
39
+ yield
40
+ font(original_name, :size => original_size)
41
+ else
42
+ @font
43
+ end
44
+ end
45
+
46
+ # Looks up the given font name. Once a font has been found by that name,
47
+ # it will be cached to subsequent lookups for that font will return the
48
+ # same object.
49
+ def find_font(name, options={}) #:nodoc:
50
+ if font_families.key?(name)
51
+ family, name = name, font_families[name][options[:style] || :normal]
52
+ end
53
+
54
+ font_registry[name] ||= Font.new(name, options.merge(:for => self, :family => family))
55
+ end
56
+
57
+ # Hash of Font objects keyed by names
58
+ #
59
+ def font_registry #:nodoc:
60
+ @font_registry ||= {}
61
+ end
62
+
63
+ # Hash that maps font family names to their styled individual font names
64
+ #
65
+ # To add support for another font family, append to this hash, e.g:
66
+ #
67
+ # pdf.font_families.update(
68
+ # "MyTrueTypeFamily" => { :bold => "foo-bold.ttf",
69
+ # :italic => "foo-italic.ttf",
70
+ # :bold_italic => "foo-bold-italic.ttf",
71
+ # :normal => "foo.ttf" })
72
+ #
73
+ # This will then allow you to use the fonts like so:
74
+ #
75
+ # pdf.font("MyTrueTypeFamily", :style => :bold)
76
+ # pdf.text "Some bold text"
77
+ # pdf.font("MyTrueTypeFamily")
78
+ # pdf.text "Some normal text"
79
+ #
80
+ # This assumes that you have appropriate TTF fonts for each style you
81
+ # wish to support.
82
+ #
83
+ def font_families
84
+ @font_families ||= Hash.new { |h,k| h[k] = {} }.merge!(
85
+ { "Courier" => { :bold => "Courier-Bold",
86
+ :italic => "Courier-Oblique",
87
+ :bold_italic => "Courier-BoldOblique",
88
+ :normal => "Courier" },
89
+
90
+ "Times-Roman" => { :bold => "Times-Bold",
91
+ :italic => "Times-Italic",
92
+ :bold_italic => "Times-BoldItalic",
93
+ :normal => "Times-Roman" },
94
+
95
+ "Helvetica" => { :bold => "Helvetica-Bold",
96
+ :italic => "Helvetica-Oblique",
97
+ :bold_italic => "Helvetica-BoldOblique",
98
+ :normal => "Helvetica" }
99
+ })
100
+ end
101
+ end
102
+
103
+ # Provides font information and helper functions.
104
+ #
105
+ class Font
106
+
107
+ BUILT_INS = %w[ Courier Helvetica Times-Roman Symbol ZapfDingbats
108
+ Courier-Bold Courier-Oblique Courier-BoldOblique
109
+ Times-Bold Times-Italic Times-BoldItalic
110
+ Helvetica-Bold Helvetica-Oblique Helvetica-BoldOblique ]
111
+
112
+ DEFAULT_SIZE = 12
113
+
114
+ # The font metrics object
115
+ attr_reader :metrics
116
+
117
+ # The current font name
118
+ attr_reader :name
119
+
120
+ # The current font family
121
+ attr_reader :family
122
+
123
+ attr_reader :identifier, :reference #:nodoc:
124
+
125
+ # Sets the size of the current font:
126
+ #
127
+ # font.size = 16
128
+ #
129
+ attr_writer :size
130
+
131
+ def initialize(name,options={}) #:nodoc:
132
+ @name = name
133
+ @family = options[:family]
134
+
135
+ @metrics = Prawn::Font::Metrics[name]
136
+ @document = options[:for]
137
+
138
+ @document.proc_set :PDF, :Text
139
+ @size = DEFAULT_SIZE
140
+ @identifier = :"F#{@document.font_registry.size + 1}"
141
+
142
+ @reference = nil
143
+ end
144
+
145
+ def inspect
146
+ "Prawn::Font< #{name}: #{size} >"
147
+ end
148
+
149
+ # Sets the default font size for use within a block. Individual overrides
150
+ # can be used as desired. The previous font size will be restored after the
151
+ # block.
152
+ #
153
+ # Prawn::Document.generate("font_size.pdf") do
154
+ # font.size = 16
155
+ # text "At size 16"
156
+ #
157
+ # font.size(10) do
158
+ # text "At size 10"
159
+ # text "At size 6", :size => 6
160
+ # text "At size 10"
161
+ # end
162
+ #
163
+ # text "At size 16"
164
+ # end
165
+ #
166
+ # When called without an argument, this method returns the current font
167
+ # size.
168
+ #
169
+ def size(points=nil)
170
+ return @size unless points
171
+ size_before_yield = @size
172
+ @size = points
173
+ yield
174
+ @size = size_before_yield
175
+ end
176
+
177
+ # Gets width of string in PDF points at current font size
178
+ #
179
+ # If using an AFM, string *must* be encoded as WinAnsi
180
+ # (Use normalize_encoding to convert)
181
+ #
182
+ def width_of(string)
183
+ @metrics.string_width(string,@size)
184
+ end
185
+
186
+ # Gets height of text in PDF points at current font size.
187
+ # Text +:line_width+ must be specified in PDF points.
188
+ #
189
+ # If using an AFM, string *must* be encoded as WinAnsi
190
+ # (Use normalize_encoding to convert)
191
+ #
192
+ def height_of(text,options={})
193
+ @metrics.string_height( text, :font_size => @size,
194
+ :line_width => options[:line_width] )
195
+ end
196
+
197
+ # Gets height of current font in PDF points at current font size
198
+ #
199
+ def height
200
+ @metrics.font_height(@size)
201
+ end
202
+
203
+ # The height of the ascender at the current font size in PDF points
204
+ #
205
+ def ascender
206
+ @metrics.ascender / 1000.0 * @size
207
+ end
208
+
209
+ # The height of the descender at the current font size in PDF points
210
+ #
211
+ def descender
212
+ @metrics.descender / 1000.0 * @size
213
+ end
214
+
215
+ def line_gap
216
+ @metrics.line_gap / 1000.0 * @size
217
+ end
218
+
219
+ def normalize_encoding(text) # :nodoc:
220
+ # check the string is encoded sanely
221
+ # - UTF-8 for TTF fonts
222
+ # - ISO-8859-1 for Built-In fonts
223
+ if @metrics.type0?
224
+ normalize_ttf_encoding(text)
225
+ else
226
+ normalize_builtin_encoding(text)
227
+ end
228
+ end
229
+
230
+ def add_to_current_page #:nodoc:
231
+ embed! unless @reference
232
+ @document.page_fonts.merge!(@identifier => @reference)
233
+ end
234
+
235
+ private
236
+
237
+ def embed!
238
+ case(name)
239
+ when /\.ttf$/i
240
+ embed_ttf(name)
241
+ else
242
+ register_builtin(name)
243
+ end
244
+ end
245
+
246
+ # built-in fonts only work with winansi encoding, so translate the string
247
+ def normalize_builtin_encoding(text)
248
+ enc = Prawn::Encoding::WinAnsi.new
249
+ text.replace text.unpack("U*").collect { |i| enc[i] }.pack("C*")
250
+ end
251
+
252
+ def normalize_ttf_encoding(text)
253
+ # TODO: if the current font is a built in one, we can't use the utf-8
254
+ # string provided by the user. We should convert it to WinAnsi or
255
+ # MacRoman or some such.
256
+ if text.respond_to?(:encode!)
257
+ # if we're running under a M17n aware VM, ensure the string provided is
258
+ # UTF-8 (by converting it if necessary)
259
+ begin
260
+ text.encode!("UTF-8")
261
+ rescue
262
+ raise Prawn::Errors::IncompatibleStringEncoding, "Encoding " +
263
+ "#{text.encoding} can not be transparently converted to UTF-8. " +
264
+ "Please ensure the encoding of the string you are attempting " +
265
+ "to use is set correctly"
266
+ end
267
+ else
268
+ # on a non M17N aware VM, use unpack as a hackish way to verify the
269
+ # string is valid utf-8. I thought it was better than loading iconv
270
+ # though.
271
+ begin
272
+ text.unpack("U*")
273
+ rescue
274
+ raise Prawn::Errors::IncompatibleStringEncoding, "The string you " +
275
+ "are attempting to render is not encoded in valid UTF-8."
276
+ end
277
+ end
278
+ end
279
+
280
+ def register_builtin(name)
281
+ unless BUILT_INS.include?(name)
282
+ raise Prawn::Errors::UnknownFont, "#{name} is not a known font."
283
+ end
284
+
285
+ @reference = @document.ref( :Type => :Font,
286
+ :Subtype => :Type1,
287
+ :BaseFont => name.to_sym,
288
+ :Encoding => :WinAnsiEncoding)
289
+ end
290
+
291
+ def embed_ttf(file)
292
+ unless File.file?(file)
293
+ raise ArgumentError, "file #{file} does not exist"
294
+ end
295
+
296
+ basename = @metrics.basename
297
+
298
+ raise "Can't detect a postscript name for #{file}" if basename.nil?
299
+
300
+ @encodings = @metrics.cmap
301
+
302
+ if @encodings.nil?
303
+ raise "#{file} missing the required encoding table"
304
+ end
305
+
306
+ font_content = File.open(file,"rb") { |f| f.read }
307
+ compressed_font = Zlib::Deflate.deflate(font_content)
308
+
309
+ fontfile = @document.ref(:Length => compressed_font.size,
310
+ :Length1 => font_content.size,
311
+ :Filter => :FlateDecode )
312
+ fontfile << compressed_font
313
+
314
+ # TODO: Not sure what to do about CapHeight, as ttf2afm doesn't
315
+ # pick it up. Missing proper StemV and flags
316
+ #
317
+ descriptor = @document.ref(:Type => :FontDescriptor,
318
+ :FontName => basename,
319
+ :FontFile2 => fontfile,
320
+ :FontBBox => @metrics.bbox,
321
+ :Flags => 32, # FIXME: additional flags
322
+ :StemV => 0,
323
+ :ItalicAngle => 0,
324
+ :Ascent => @metrics.ascender,
325
+ :Descent => @metrics.descender )
326
+
327
+ descendant = @document.ref(:Type => :Font,
328
+ :Subtype => :CIDFontType2, # CID, TTF
329
+ :BaseFont => basename,
330
+ :CIDSystemInfo => { :Registry => "Adobe",
331
+ :Ordering => "Identity",
332
+ :Supplement => 0 },
333
+ :FontDescriptor => descriptor,
334
+ :W => @metrics.glyph_widths,
335
+ :CIDToGIDMap => :Identity )
336
+
337
+ to_unicode_content = @metrics.to_unicode_cmap.to_s
338
+ compressed_to_unicode = Zlib::Deflate.deflate(to_unicode_content)
339
+
340
+ to_unicode = @document.ref(:Length => compressed_to_unicode.size,
341
+ :Length1 => to_unicode_content.size,
342
+ :Filter => :FlateDecode )
343
+ to_unicode << compressed_to_unicode
344
+
345
+ @reference = @document.ref(:Type => :Font,
346
+ :Subtype => :Type0,
347
+ :BaseFont => basename,
348
+ :DescendantFonts => [descendant],
349
+ :Encoding => :"Identity-H",
350
+ :ToUnicode => to_unicode)
351
+
352
+ end
353
+
354
+ end
355
+
356
+ end