giga-fast-kit 0.0.1

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 (75) hide show
  1. checksums.yaml +7 -0
  2. data/giga-fast-kit.gemspec +12 -0
  3. data/prawn-2.5.0/COPYING +2 -0
  4. data/prawn-2.5.0/GPLv2 +339 -0
  5. data/prawn-2.5.0/GPLv3 +674 -0
  6. data/prawn-2.5.0/LICENSE +56 -0
  7. data/prawn-2.5.0/data/fonts/Courier-Bold.afm +342 -0
  8. data/prawn-2.5.0/data/fonts/Courier-BoldOblique.afm +342 -0
  9. data/prawn-2.5.0/data/fonts/Courier-Oblique.afm +342 -0
  10. data/prawn-2.5.0/data/fonts/Courier.afm +342 -0
  11. data/prawn-2.5.0/data/fonts/Helvetica-Bold.afm +2827 -0
  12. data/prawn-2.5.0/data/fonts/Helvetica-BoldOblique.afm +2827 -0
  13. data/prawn-2.5.0/data/fonts/Helvetica-Oblique.afm +3051 -0
  14. data/prawn-2.5.0/data/fonts/Helvetica.afm +3051 -0
  15. data/prawn-2.5.0/data/fonts/MustRead.html +19 -0
  16. data/prawn-2.5.0/data/fonts/Symbol.afm +213 -0
  17. data/prawn-2.5.0/data/fonts/Times-Bold.afm +2588 -0
  18. data/prawn-2.5.0/data/fonts/Times-BoldItalic.afm +2384 -0
  19. data/prawn-2.5.0/data/fonts/Times-Italic.afm +2667 -0
  20. data/prawn-2.5.0/data/fonts/Times-Roman.afm +2419 -0
  21. data/prawn-2.5.0/data/fonts/ZapfDingbats.afm +225 -0
  22. data/prawn-2.5.0/lib/prawn/document/bounding_box.rb +625 -0
  23. data/prawn-2.5.0/lib/prawn/document/column_box.rb +177 -0
  24. data/prawn-2.5.0/lib/prawn/document/internals.rb +76 -0
  25. data/prawn-2.5.0/lib/prawn/document/span.rb +65 -0
  26. data/prawn-2.5.0/lib/prawn/document.rb +846 -0
  27. data/prawn-2.5.0/lib/prawn/encoding.rb +85 -0
  28. data/prawn-2.5.0/lib/prawn/errors.rb +73 -0
  29. data/prawn-2.5.0/lib/prawn/font.rb +567 -0
  30. data/prawn-2.5.0/lib/prawn/font_metric_cache.rb +50 -0
  31. data/prawn-2.5.0/lib/prawn/fonts/afm.rb +332 -0
  32. data/prawn-2.5.0/lib/prawn/fonts/dfont.rb +42 -0
  33. data/prawn-2.5.0/lib/prawn/fonts/otf.rb +14 -0
  34. data/prawn-2.5.0/lib/prawn/fonts/to_unicode_cmap.rb +151 -0
  35. data/prawn-2.5.0/lib/prawn/fonts/ttc.rb +41 -0
  36. data/prawn-2.5.0/lib/prawn/fonts/ttf.rb +615 -0
  37. data/prawn-2.5.0/lib/prawn/fonts.rb +14 -0
  38. data/prawn-2.5.0/lib/prawn/graphics/blend_mode.rb +62 -0
  39. data/prawn-2.5.0/lib/prawn/graphics/cap_style.rb +44 -0
  40. data/prawn-2.5.0/lib/prawn/graphics/color.rb +257 -0
  41. data/prawn-2.5.0/lib/prawn/graphics/dash.rb +123 -0
  42. data/prawn-2.5.0/lib/prawn/graphics/join_style.rb +60 -0
  43. data/prawn-2.5.0/lib/prawn/graphics/patterns.rb +389 -0
  44. data/prawn-2.5.0/lib/prawn/graphics/transformation.rb +172 -0
  45. data/prawn-2.5.0/lib/prawn/graphics/transparency.rb +79 -0
  46. data/prawn-2.5.0/lib/prawn/graphics.rb +791 -0
  47. data/prawn-2.5.0/lib/prawn/grid.rb +449 -0
  48. data/prawn-2.5.0/lib/prawn/image_handler.rb +61 -0
  49. data/prawn-2.5.0/lib/prawn/images/image.rb +48 -0
  50. data/prawn-2.5.0/lib/prawn/images/jpg.rb +121 -0
  51. data/prawn-2.5.0/lib/prawn/images/png.rb +383 -0
  52. data/prawn-2.5.0/lib/prawn/images.rb +195 -0
  53. data/prawn-2.5.0/lib/prawn/measurement_extensions.rb +82 -0
  54. data/prawn-2.5.0/lib/prawn/measurements.rb +129 -0
  55. data/prawn-2.5.0/lib/prawn/outline.rb +316 -0
  56. data/prawn-2.5.0/lib/prawn/repeater.rb +140 -0
  57. data/prawn-2.5.0/lib/prawn/security/arcfour.rb +54 -0
  58. data/prawn-2.5.0/lib/prawn/security.rb +308 -0
  59. data/prawn-2.5.0/lib/prawn/soft_mask.rb +105 -0
  60. data/prawn-2.5.0/lib/prawn/stamp.rb +147 -0
  61. data/prawn-2.5.0/lib/prawn/text/box.rb +192 -0
  62. data/prawn-2.5.0/lib/prawn/text/formatted/arranger.rb +396 -0
  63. data/prawn-2.5.0/lib/prawn/text/formatted/box.rb +725 -0
  64. data/prawn-2.5.0/lib/prawn/text/formatted/fragment.rb +373 -0
  65. data/prawn-2.5.0/lib/prawn/text/formatted/line_wrap.rb +335 -0
  66. data/prawn-2.5.0/lib/prawn/text/formatted/parser.rb +284 -0
  67. data/prawn-2.5.0/lib/prawn/text/formatted/wrap.rb +166 -0
  68. data/prawn-2.5.0/lib/prawn/text/formatted.rb +82 -0
  69. data/prawn-2.5.0/lib/prawn/text.rb +701 -0
  70. data/prawn-2.5.0/lib/prawn/transformation_stack.rb +63 -0
  71. data/prawn-2.5.0/lib/prawn/utilities.rb +34 -0
  72. data/prawn-2.5.0/lib/prawn/version.rb +6 -0
  73. data/prawn-2.5.0/lib/prawn/view.rb +116 -0
  74. data/prawn-2.5.0/lib/prawn.rb +83 -0
  75. metadata +114 -0
@@ -0,0 +1,383 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'stringio'
5
+ module Prawn
6
+ module Images # rubocop: disable Style/Documentation
7
+ # A convenience class that wraps the logic for extracting the parts of a PNG
8
+ # image that we need to embed them in a PDF.
9
+ class PNG < Image
10
+ # @group Extension API
11
+
12
+ # Palette data.
13
+ # @return [String]
14
+ attr_reader :palette
15
+
16
+ # Image data.
17
+ # @return [String]
18
+ attr_reader :img_data
19
+
20
+ # Transparency data.
21
+ # @return [Hash{Symbol => String}]
22
+ attr_reader :transparency
23
+
24
+ # Image width in pixels.
25
+ # @return [Integer]
26
+ attr_reader :width
27
+
28
+ # Image height in pixels.
29
+ # @return [Integer]
30
+ attr_reader :height
31
+
32
+ # Bits per sample or per palette index.
33
+ # @return [Integer]
34
+ attr_reader :bits
35
+
36
+ # Color type.
37
+ # @return [Integer]
38
+ attr_reader :color_type
39
+
40
+ # Compression method.
41
+ # @return [Integer]
42
+ attr_reader :compression_method
43
+
44
+ # Filter method.
45
+ # @return [Integer]
46
+ attr_reader :filter_method
47
+
48
+ # Interlace method.
49
+ # @return [Integer]
50
+ attr_reader :interlace_method
51
+
52
+ # Extracted alpha-channel.
53
+ # @return [String, nil]
54
+ attr_reader :alpha_channel
55
+
56
+ # Scaled width of the image in PDF points.
57
+ # @return [Number]
58
+ attr_accessor :scaled_width
59
+
60
+ # Scaled height of the image in PDF points.
61
+ # @return [Number]
62
+ attr_accessor :scaled_height
63
+
64
+ # Can this image handler process this image?
65
+ #
66
+ # @param image_blob [String]
67
+ # @return [Boolean]
68
+ def self.can_render?(image_blob)
69
+ image_blob[0, 8].unpack('C*') == [137, 80, 78, 71, 13, 10, 26, 10]
70
+ end
71
+
72
+ # Process a new PNG image
73
+ #
74
+ # @param data [String] A binary string of PNG data.
75
+ def initialize(data)
76
+ super()
77
+ data = StringIO.new(data.dup)
78
+
79
+ data.read(8) # Skip the default header
80
+
81
+ @palette = +''
82
+ @img_data = +''
83
+ @transparency = {}
84
+
85
+ loop do
86
+ chunk_size = data.read(4).unpack1('N')
87
+ section = data.read(4)
88
+ case section
89
+ when 'IHDR'
90
+ # we can grab other interesting values from here (like width,
91
+ # height, etc)
92
+ values = data.read(chunk_size).unpack('NNCCCCC')
93
+
94
+ @width = values[0]
95
+ @height = values[1]
96
+ @bits = values[2]
97
+ @color_type = values[3]
98
+ @compression_method = values[4]
99
+ @filter_method = values[5]
100
+ @interlace_method = values[6]
101
+ when 'PLTE'
102
+ @palette << data.read(chunk_size)
103
+ when 'IDAT'
104
+ @img_data << data.read(chunk_size)
105
+ when 'tRNS'
106
+ # This chunk can only occur once and it must occur after the
107
+ # PLTE chunk and before the IDAT chunk
108
+ @transparency = {}
109
+ case @color_type
110
+ when 3
111
+ @transparency[:palette] = data.read(chunk_size).unpack('C*')
112
+ when 0
113
+ # Greyscale. Corresponding to entries in the PLTE chunk.
114
+ # Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
115
+ grayval = data.read(chunk_size).unpack1('n')
116
+ @transparency[:grayscale] = grayval
117
+ when 2
118
+ # True colour with proper alpha channel.
119
+ @transparency[:rgb] = data.read(chunk_size).unpack('nnn')
120
+ end
121
+ when 'IEND'
122
+ # we've got everything we need, exit the loop
123
+ break
124
+ else
125
+ # unknown (or un-important) section, skip over it
126
+ data.seek(data.pos + chunk_size)
127
+ end
128
+
129
+ data.read(4) # Skip the CRC
130
+ end
131
+
132
+ @img_data = Zlib::Inflate.inflate(@img_data)
133
+ end
134
+
135
+ # Number of color components to each pixel.
136
+ #
137
+ # @return [Integer]
138
+ def colors
139
+ case color_type
140
+ when 0, 3, 4
141
+ 1
142
+ when 2, 6
143
+ 3
144
+ end
145
+ end
146
+
147
+ # Split the alpha channel data from the raw image data in images where
148
+ # it's required.
149
+ #
150
+ # @private
151
+ # @return [void]
152
+ def split_alpha_channel!
153
+ if alpha_channel?
154
+ if color_type == 3
155
+ generate_alpha_channel
156
+ else
157
+ split_image_data
158
+ end
159
+ end
160
+ end
161
+
162
+ # Is there an alpha-channel in this image?
163
+ #
164
+ # @return [Boolean]
165
+ def alpha_channel?
166
+ return true if color_type == 4 || color_type == 6
167
+ return @transparency.any? if color_type == 3
168
+
169
+ false
170
+ end
171
+
172
+ # Build a PDF object representing this image in `document`, and return
173
+ # a Reference to it.
174
+ #
175
+ # @param document [Prawn::Document]
176
+ # @return [PDF::Core::Reference]
177
+ def build_pdf_object(document)
178
+ if compression_method != 0
179
+ raise Errors::UnsupportedImageType,
180
+ 'PNG uses an unsupported compression method'
181
+ end
182
+
183
+ if filter_method != 0
184
+ raise Errors::UnsupportedImageType,
185
+ 'PNG uses an unsupported filter method'
186
+ end
187
+
188
+ if interlace_method != 0
189
+ raise Errors::UnsupportedImageType,
190
+ 'PNG uses unsupported interlace method'
191
+ end
192
+
193
+ # some PNG types store the colour and alpha channel data together,
194
+ # which the PDF spec doesn't like, so split it out.
195
+ split_alpha_channel!
196
+
197
+ case colors
198
+ when 1
199
+ color = :DeviceGray
200
+ when 3
201
+ color = :DeviceRGB
202
+ else
203
+ raise Errors::UnsupportedImageType,
204
+ "PNG uses an unsupported number of colors (#{png.colors})"
205
+ end
206
+
207
+ # build the image dict
208
+ obj = document.ref!(
209
+ Type: :XObject,
210
+ Subtype: :Image,
211
+ Height: height,
212
+ Width: width,
213
+ BitsPerComponent: bits,
214
+ )
215
+
216
+ # append the actual image data to the object as a stream
217
+ obj << img_data
218
+
219
+ obj.stream.filters << {
220
+ FlateDecode: {
221
+ Predictor: 15,
222
+ Colors: colors,
223
+ BitsPerComponent: bits,
224
+ Columns: width,
225
+ },
226
+ }
227
+
228
+ # sort out the colours of the image
229
+ if palette.empty?
230
+ obj.data[:ColorSpace] = color
231
+ else
232
+ # embed the colour palette in the PDF as a object stream
233
+ palette_obj = document.ref!({})
234
+ palette_obj << palette
235
+
236
+ # build the color space array for the image
237
+ obj.data[:ColorSpace] = [
238
+ :Indexed,
239
+ :DeviceRGB,
240
+ (palette.size / 3) - 1,
241
+ palette_obj,
242
+ ]
243
+ end
244
+
245
+ # *************************************
246
+ # add transparency data if necessary
247
+ # *************************************
248
+
249
+ # For PNG color types 0, 2 and 3, the transparency data is stored in
250
+ # a dedicated PNG chunk, and is exposed via the transparency attribute
251
+ # of the PNG class.
252
+ if transparency[:grayscale]
253
+ # Use Color Key Masking (spec section 4.8.5)
254
+ # - An array with N elements, where N is two times the number of color
255
+ # components.
256
+ val = transparency[:grayscale]
257
+ obj.data[:Mask] = [val, val]
258
+ elsif transparency[:rgb]
259
+ # Use Color Key Masking (spec section 4.8.5)
260
+ # - An array with N elements, where N is two times the number of color
261
+ # components.
262
+ rgb = transparency[:rgb]
263
+ obj.data[:Mask] = rgb.map { |x| [x, x] }.flatten
264
+ end
265
+
266
+ # For PNG color types 4 and 6, the transparency data is stored as
267
+ # a alpha channel mixed in with the main image data. The PNG class
268
+ # separates it out for us and makes it available via the alpha_channel
269
+ # attribute
270
+ if alpha_channel?
271
+ smask_obj = document.ref!(
272
+ Type: :XObject,
273
+ Subtype: :Image,
274
+ Height: height,
275
+ Width: width,
276
+ BitsPerComponent: bits,
277
+ ColorSpace: :DeviceGray,
278
+ Decode: [0, 1],
279
+ )
280
+ smask_obj.stream << alpha_channel
281
+
282
+ smask_obj.stream.filters << {
283
+ FlateDecode: {
284
+ Predictor: 15,
285
+ Colors: 1,
286
+ BitsPerComponent: bits,
287
+ Columns: width,
288
+ },
289
+ }
290
+ obj.data[:SMask] = smask_obj
291
+ end
292
+
293
+ obj
294
+ end
295
+
296
+ # Returns the minimum PDF version required to support this image.
297
+ #
298
+ # @return [Float]
299
+ def min_pdf_version
300
+ if bits > 8
301
+ # 16-bit color only supported in 1.5+ (ISO 32000-1:2008 8.9.5.1)
302
+ 1.5
303
+ elsif alpha_channel?
304
+ # Need transparency for SMask
305
+ 1.4
306
+ else
307
+ 1.0
308
+ end
309
+ end
310
+
311
+ private
312
+
313
+ def split_image_data
314
+ alpha_bytes = bits / 8
315
+ color_bytes = colors * bits / 8
316
+
317
+ scanline_length = ((color_bytes + alpha_bytes) * width) + 1
318
+ scanlines = @img_data.bytesize / scanline_length
319
+ pixels = width * height
320
+
321
+ data = StringIO.new(@img_data)
322
+ data.binmode
323
+
324
+ color_data = [0x00].pack('C') * ((pixels * color_bytes) + scanlines)
325
+ color = StringIO.new(color_data)
326
+ color.binmode
327
+
328
+ @alpha_channel = [0x00].pack('C') * ((pixels * alpha_bytes) + scanlines)
329
+ alpha = StringIO.new(@alpha_channel)
330
+ alpha.binmode
331
+
332
+ scanlines.times do |line|
333
+ data.seek(line * scanline_length)
334
+
335
+ filter = data.getbyte
336
+
337
+ color.putc(filter)
338
+ alpha.putc(filter)
339
+
340
+ width.times do
341
+ color.write(data.read(color_bytes))
342
+ alpha.write(data.read(alpha_bytes))
343
+ end
344
+ end
345
+
346
+ @img_data = color_data
347
+ end
348
+
349
+ def generate_alpha_channel
350
+ alpha_palette = Hash.new(0xff)
351
+ 0.upto(palette.bytesize / 3) do |n|
352
+ alpha_palette[n] = @transparency[:palette][n] || 0xff
353
+ end
354
+
355
+ scanline_length = width + 1
356
+ scanlines = @img_data.bytesize / scanline_length
357
+ pixels = width * height
358
+
359
+ data = StringIO.new(@img_data)
360
+ data.binmode
361
+
362
+ @alpha_channel = [0x00].pack('C') * (pixels + scanlines)
363
+ alpha = StringIO.new(@alpha_channel)
364
+ alpha.binmode
365
+
366
+ scanlines.times do |line|
367
+ data.seek(line * scanline_length)
368
+
369
+ filter = data.getbyte
370
+
371
+ alpha.putc(filter)
372
+
373
+ width.times do
374
+ color = data.read(1).unpack1('C')
375
+ alpha.putc(alpha_palette[color])
376
+ end
377
+ end
378
+ end
379
+ end
380
+
381
+ Prawn.image_handler.register(Prawn::Images::PNG)
382
+ end
383
+ end
@@ -0,0 +1,195 @@
1
+ # encoding: ASCII-8BIT
2
+ # frozen_string_literal: true
3
+
4
+ require 'digest/sha1'
5
+ require 'pathname'
6
+
7
+ module Prawn
8
+ # PDF image embedding.
9
+ module Images
10
+ # @group Stable API
11
+
12
+ # Add the image at `file` to the current page. Currently only JPG and
13
+ # PNG files are supported. (Note that processing PNG images with alpha
14
+ # channels can be processor and memory intensive.)
15
+ #
16
+ # If only one of `:width` or `:height` are provided, the image will be
17
+ # scaled proportionally. When both are provided, the image will be stretched
18
+ # to fit the dimensions without maintaining the aspect ratio.
19
+ #
20
+ # @example
21
+ # Prawn::Document.generate("image2.pdf", page_layout: :landscape) do
22
+ # pigs = "#{Prawn::DATADIR}/images/pigs.jpg"
23
+ # image pigs, at: [50,450], width: 450
24
+ #
25
+ # dice = "#{Prawn::DATADIR}/images/dice.png"
26
+ # image dice, at: [50, 450], scale: 0.75
27
+ # end
28
+ #
29
+ # @param file [String, IO]
30
+ # Path to file or an object that responds to `#read` and `#rewind`.
31
+ # @param options [Hash{Symbol => any}]
32
+ # @option options :at [Array(Number, Number)]
33
+ # The location of the top left corner of the image. If provided,
34
+ # the image will be place in the current page but the text position will
35
+ # not be changed.
36
+ # @option options :position [:left, :center, :right, Number]
37
+ # Horizontal position relative to the current bounding box.
38
+ # @option options :vposition [:topm :center, :bottom, Number]
39
+ # Vertical position relative to the current bounding box.
40
+ # @option options :height [Number] (actual height of the image)
41
+ # The height of the image.
42
+ # @option options :width [Number] (actual width of the image)
43
+ # The width of the image.
44
+ # @option options :scale [Number]
45
+ # Scale the dimensions of the image proportionally.
46
+ # @option options :fit [Array(Number, Number)]
47
+ # Scale the dimensions of the image proportionally to fit
48
+ # inside the rectangle of specified size (width, height).
49
+ # @return [Prawn::Images::Image]
50
+ # An image handler. All image handlers provided by Prawn are subclasses of
51
+ # {Prawn::Images::Image}. This object can be used to check the image
52
+ # dimensions and get other format-specific information.
53
+ #
54
+ # @see Prawn::Images::PNG
55
+ # @see Prawn::Images::JPG
56
+ def image(file, options = {})
57
+ Prawn.verify_options(
58
+ %i[at position vposition height width scale fit],
59
+ options,
60
+ )
61
+
62
+ pdf_obj, info = build_image_object(file)
63
+ embed_image(pdf_obj, info, options)
64
+
65
+ info
66
+ end
67
+
68
+ # Builds an info object (Prawn::Images::*) and a PDF reference representing
69
+ # the given image. Return a pair: [pdf_obj, info].
70
+ #
71
+ # @private
72
+ def build_image_object(file)
73
+ image_content = verify_and_read_image(file)
74
+ image_sha1 = Digest::SHA1.hexdigest(image_content)
75
+
76
+ # if this image has already been embedded, just reuse it
77
+ if image_registry[image_sha1]
78
+ info = image_registry[image_sha1][:info]
79
+ image_obj = image_registry[image_sha1][:obj]
80
+ else
81
+ # Build the image object
82
+ info = Prawn.image_handler.find(image_content).new(image_content)
83
+
84
+ # Bump PDF version if the image requires it
85
+ if info.respond_to?(:min_pdf_version)
86
+ renderer.min_version(info.min_pdf_version)
87
+ end
88
+
89
+ # Add the image to the PDF and register it in case we see it again.
90
+ image_obj = info.build_pdf_object(self)
91
+ image_registry[image_sha1] = { obj: image_obj, info: info }
92
+ end
93
+
94
+ [image_obj, info]
95
+ end
96
+
97
+ # Given a PDF image resource `pdf_obj` that has been added to the page's
98
+ # resources and an `info` object (the pair returned from
99
+ # {build_image_object}), embed the image according to the `options` given.
100
+ #
101
+ # @private
102
+ def embed_image(pdf_obj, info, options)
103
+ # find where the image will be placed and how big it will be
104
+ w, h = info.calc_image_dimensions(options)
105
+
106
+ if options[:at]
107
+ x, y = map_to_absolute(options[:at])
108
+ else
109
+ x, y = image_position(w, h, options)
110
+ move_text_position(h)
111
+ end
112
+
113
+ # add a reference to the image object to the current page
114
+ # resource list and give it a label
115
+ label = "I#{next_image_id}"
116
+ state.page.xobjects[label] = pdf_obj
117
+
118
+ cm_params = PDF::Core.real_params([w, 0, 0, h, x, y - h])
119
+ renderer.add_content("\nq\n#{cm_params} cm\n/#{label} Do\nQ")
120
+ end
121
+
122
+ private
123
+
124
+ def verify_and_read_image(io_or_path)
125
+ # File or IO
126
+ if io_or_path.respond_to?(:rewind)
127
+ io = io_or_path
128
+ # Rewind if the object we're passed is an IO, so that multiple embeds of
129
+ # the same IO object will work
130
+ io.rewind
131
+ # read the file as binary so the size is calculated correctly
132
+ # guard binmode because some objects acting io-like don't implement it
133
+ io.binmode if io.respond_to?(:binmode)
134
+ return io.read
135
+ end
136
+ # String or Pathname
137
+ io_or_path = Pathname.new(io_or_path)
138
+ raise ArgumentError, "#{io_or_path} not found" unless io_or_path.file?
139
+
140
+ io_or_path.binread
141
+ end
142
+
143
+ def image_position(width, height, options)
144
+ options[:position] ||= :left
145
+
146
+ y =
147
+ case options[:vposition]
148
+ when :top
149
+ bounds.absolute_top
150
+ when :center
151
+ bounds.absolute_top - ((bounds.height - height) / 2.0)
152
+ when :bottom
153
+ bounds.absolute_bottom + height
154
+ when Numeric
155
+ bounds.absolute_top - options[:vposition]
156
+ else
157
+ determine_y_with_page_flow(height)
158
+ end
159
+
160
+ x =
161
+ case options[:position]
162
+ when :left
163
+ bounds.left_side
164
+ when :center
165
+ bounds.left_side + ((bounds.width - width) / 2.0)
166
+ when :right
167
+ bounds.right_side - width
168
+ when Numeric
169
+ options[:position] + bounds.left_side
170
+ end
171
+
172
+ [x, y]
173
+ end
174
+
175
+ def determine_y_with_page_flow(height)
176
+ if overruns_page?(height)
177
+ bounds.move_past_bottom
178
+ end
179
+ y
180
+ end
181
+
182
+ def overruns_page?(height)
183
+ (y - height) < reference_bounds.absolute_bottom
184
+ end
185
+
186
+ def image_registry
187
+ @image_registry ||= {}
188
+ end
189
+
190
+ def next_image_id
191
+ @image_counter ||= 0
192
+ @image_counter += 1
193
+ end
194
+ end
195
+ end
@@ -0,0 +1,82 @@
1
+ # frozen_string_literal: true
2
+
3
+ require_relative 'measurements'
4
+
5
+ # @group Stable API
6
+
7
+ # Core extensions for {Prawn::Measurements}.
8
+ #
9
+ # This mainly enables measurements DSL.
10
+ #
11
+ # You have to explicitly require "prawn/measurement_extensions" to enable these.
12
+ #
13
+ # ```ruby
14
+ # require 'prawn/measurement_extensions'
15
+ #
16
+ # 12.mm
17
+ # 2.cm
18
+ # 0.5.in
19
+ # 4.yd + 2.ft
20
+ # ```
21
+ class Numeric
22
+ include Prawn::Measurements
23
+ # Prawn's basic unit is PostScript-Point: 72 points per inch.
24
+
25
+ # @group Experimental API
26
+
27
+ # Convert from millimeters to points.
28
+ #
29
+ # @return [Number]
30
+ def mm
31
+ mm2pt(self)
32
+ end
33
+
34
+ # Convert from centimeters to points.
35
+ #
36
+ # @return [Number]
37
+ def cm
38
+ cm2pt(self)
39
+ end
40
+
41
+ # Convert from decimeters to points.
42
+ #
43
+ # @return [Number]
44
+ def dm
45
+ dm2pt(self)
46
+ end
47
+
48
+ # Convert from meters to points.
49
+ #
50
+ # @return [Number]
51
+ def m
52
+ m2pt(self)
53
+ end
54
+
55
+ # Convert from inches to points.
56
+ #
57
+ # @return [Number]
58
+ def in
59
+ in2pt(self)
60
+ end
61
+
62
+ # Convert from yards to points.
63
+ #
64
+ # @return [Number]
65
+ def yd
66
+ yd2pt(self)
67
+ end
68
+
69
+ # Convert from feet to points.
70
+ #
71
+ # @return [Number]
72
+ def ft
73
+ ft2pt(self)
74
+ end
75
+
76
+ # Convert from points to points.
77
+ #
78
+ # @return [Number]
79
+ def pt
80
+ pt2pt(self)
81
+ end
82
+ end