prawn 0.13.0 → 2.4.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.
- checksums.yaml +5 -5
- checksums.yaml.gz.sig +0 -0
- data/.yardopts +10 -0
- data/GPLv2 +20 -21
- data/Gemfile +3 -16
- data/Rakefile +17 -39
- data/lib/prawn/document/bounding_box.rb +85 -42
- data/lib/prawn/document/column_box.rb +21 -11
- data/lib/prawn/document/internals.rb +40 -147
- data/lib/prawn/document/span.rb +25 -17
- data/lib/prawn/document.rb +286 -245
- data/lib/prawn/encoding.rb +68 -101
- data/lib/prawn/errors.rb +47 -43
- data/lib/prawn/font.rb +204 -155
- data/lib/prawn/font_metric_cache.rb +25 -21
- data/lib/prawn/fonts/afm.rb +292 -0
- data/lib/prawn/{font → fonts}/dfont.rb +7 -13
- data/lib/prawn/fonts/otf.rb +11 -0
- data/lib/prawn/fonts/ttc.rb +36 -0
- data/lib/prawn/{font → fonts}/ttf.rb +142 -80
- data/lib/prawn/graphics/blend_mode.rb +65 -0
- data/lib/prawn/graphics/cap_style.rb +6 -5
- data/lib/prawn/graphics/color.rb +47 -44
- data/lib/prawn/graphics/dash.rb +30 -13
- data/lib/prawn/graphics/join_style.rb +13 -6
- data/lib/prawn/graphics/patterns.rb +221 -90
- data/lib/prawn/graphics/transformation.rb +21 -12
- data/lib/prawn/graphics/transparency.rb +21 -17
- data/lib/prawn/graphics.rb +155 -128
- data/lib/prawn/{layout/grid.rb → grid.rb} +110 -47
- data/lib/prawn/image_handler.rb +16 -2
- data/lib/prawn/images/image.rb +4 -2
- data/lib/prawn/images/jpg.rb +39 -30
- data/lib/prawn/images/png.rb +132 -169
- data/lib/prawn/images.rb +70 -62
- data/lib/prawn/measurement_extensions.rb +15 -10
- data/lib/prawn/measurements.rb +22 -23
- data/lib/prawn/outline.rb +301 -13
- data/lib/prawn/repeater.rb +19 -17
- data/lib/prawn/security/arcfour.rb +54 -0
- data/lib/prawn/security.rb +108 -86
- data/lib/prawn/soft_mask.rb +40 -41
- data/lib/prawn/stamp.rb +29 -12
- data/lib/prawn/text/box.rb +27 -29
- data/lib/prawn/text/formatted/arranger.rb +110 -67
- data/lib/prawn/text/formatted/box.rb +233 -165
- data/lib/prawn/text/formatted/fragment.rb +27 -27
- data/lib/prawn/text/formatted/line_wrap.rb +137 -97
- data/lib/prawn/text/formatted/parser.rb +149 -127
- data/lib/prawn/text/formatted/wrap.rb +57 -37
- data/lib/prawn/text/formatted.rb +6 -4
- data/lib/prawn/text.rb +105 -73
- data/lib/prawn/transformation_stack.rb +44 -0
- data/lib/prawn/utilities.rb +11 -21
- data/lib/prawn/version.rb +5 -0
- data/lib/prawn/view.rb +101 -0
- data/lib/prawn.rb +42 -68
- data/{data/images/fractal.jpg → manual/absolute_position.pdf} +0 -0
- data/manual/basic_concepts/adding_pages.rb +9 -10
- data/manual/basic_concepts/basic_concepts.rb +33 -24
- data/manual/basic_concepts/creation.rb +10 -11
- data/manual/basic_concepts/cursor.rb +9 -10
- data/manual/basic_concepts/measurement.rb +10 -11
- data/manual/basic_concepts/origin.rb +8 -9
- data/manual/basic_concepts/other_cursor_helpers.rb +17 -18
- data/manual/basic_concepts/view.rb +48 -0
- data/manual/bounding_box/bounding_box.rb +31 -29
- data/manual/bounding_box/bounds.rb +17 -18
- data/manual/bounding_box/canvas.rb +8 -9
- data/manual/bounding_box/creation.rb +8 -9
- data/manual/bounding_box/indentation.rb +22 -23
- data/manual/bounding_box/nesting.rb +32 -25
- data/manual/bounding_box/russian_boxes.rb +19 -19
- data/manual/bounding_box/stretchy.rb +18 -20
- data/manual/contents.rb +35 -0
- data/manual/cover.rb +43 -0
- data/manual/document_and_page_options/background.rb +16 -14
- data/manual/document_and_page_options/document_and_page_options.rb +26 -23
- data/manual/document_and_page_options/metadata.rb +21 -19
- data/manual/document_and_page_options/page_margins.rb +20 -22
- data/manual/document_and_page_options/page_size.rb +15 -15
- data/manual/document_and_page_options/print_scaling.rb +23 -0
- data/manual/example_helper.rb +5 -408
- data/manual/graphics/blend_mode.rb +52 -0
- data/manual/graphics/circle_and_ellipse.rb +8 -9
- data/manual/graphics/color.rb +11 -13
- data/manual/graphics/common_lines.rb +13 -12
- data/manual/graphics/fill_and_stroke.rb +10 -11
- data/manual/graphics/fill_rules.rb +13 -12
- data/manual/graphics/gradients.rb +28 -22
- data/manual/graphics/graphics.rb +52 -46
- data/manual/graphics/helper.rb +20 -10
- data/manual/graphics/line_width.rb +13 -12
- data/manual/graphics/lines_and_curves.rb +13 -14
- data/manual/graphics/polygon.rb +10 -12
- data/manual/graphics/rectangle.rb +7 -8
- data/manual/graphics/rotate.rb +9 -12
- data/manual/graphics/scale.rb +19 -18
- data/manual/graphics/soft_masks.rb +5 -7
- data/manual/graphics/stroke_cap.rb +10 -11
- data/manual/graphics/stroke_dash.rb +16 -17
- data/manual/graphics/stroke_join.rb +10 -11
- data/manual/graphics/translate.rb +13 -13
- data/manual/graphics/transparency.rb +11 -13
- data/manual/{manual/how_to_read_this_manual.rb → how_to_read_this_manual.rb} +23 -25
- data/manual/images/absolute_position.rb +9 -10
- data/manual/images/fit.rb +9 -10
- data/manual/images/horizontal.rb +13 -14
- data/manual/images/images.rb +31 -30
- data/manual/images/plain_image.rb +6 -7
- data/manual/images/scale.rb +12 -13
- data/manual/images/vertical.rb +19 -17
- data/manual/images/width_and_height.rb +13 -14
- data/manual/layout/boxes.rb +14 -15
- data/manual/layout/content.rb +12 -13
- data/manual/layout/layout.rb +19 -20
- data/manual/layout/simple_grid.rb +8 -9
- data/manual/outline/add_subsection_to.rb +26 -27
- data/manual/outline/insert_section_after.rb +19 -20
- data/manual/outline/outline.rb +23 -22
- data/manual/outline/sections_and_pages.rb +24 -25
- data/manual/repeatable_content/alternate_page_numbering.rb +36 -0
- data/manual/repeatable_content/page_numbering.rb +20 -19
- data/manual/repeatable_content/repeatable_content.rb +26 -22
- data/manual/repeatable_content/repeater.rb +18 -19
- data/manual/repeatable_content/stamp.rb +18 -19
- data/manual/security/encryption.rb +8 -11
- data/manual/security/permissions.rb +20 -15
- data/manual/security/security.rb +20 -20
- data/manual/table.rb +16 -0
- data/manual/text/alignment.rb +17 -18
- data/manual/text/color.rb +13 -13
- data/manual/text/column_box.rb +10 -12
- data/manual/text/fallback_fonts.rb +29 -25
- data/manual/text/font.rb +17 -18
- data/manual/text/font_size.rb +21 -22
- data/manual/text/font_style.rb +12 -10
- data/manual/text/formatted_callbacks.rb +36 -26
- data/manual/text/formatted_text.rb +41 -34
- data/manual/text/free_flowing_text.rb +28 -29
- data/manual/text/inline.rb +23 -26
- data/manual/text/kerning_and_character_spacing.rb +20 -21
- data/manual/text/leading.rb +10 -11
- data/manual/text/line_wrapping.rb +40 -21
- data/manual/text/paragraph_indentation.rb +17 -12
- data/manual/text/positioned_text.rb +19 -20
- data/manual/text/registering_families.rb +33 -30
- data/manual/text/rendering_and_color.rb +11 -12
- data/manual/text/right_to_left_text.rb +31 -20
- data/manual/text/rotation.rb +36 -27
- data/manual/text/single_usage.rb +13 -14
- data/manual/text/text.rb +62 -62
- data/manual/text/text_box_excess.rb +22 -19
- data/manual/text/text_box_extensions.rb +21 -18
- data/manual/text/text_box_overflow.rb +28 -21
- data/manual/text/utf8.rb +16 -17
- data/manual/text/win_ansi_charset.rb +29 -26
- data/prawn.gemspec +45 -43
- data/spec/extensions/encoding_helpers.rb +4 -3
- data/spec/prawn/document/bounding_box_spec.rb +550 -0
- data/spec/prawn/document/column_box_spec.rb +75 -0
- data/spec/prawn/document/security_spec.rb +176 -0
- data/spec/prawn/document_annotations_spec.rb +76 -0
- data/spec/prawn/document_destinations_spec.rb +15 -0
- data/spec/prawn/document_grid_spec.rb +99 -0
- data/spec/prawn/document_reference_spec.rb +27 -0
- data/spec/prawn/document_span_spec.rb +44 -0
- data/spec/prawn/document_spec.rb +805 -0
- data/spec/prawn/font_metric_cache_spec.rb +54 -0
- data/spec/prawn/font_spec.rb +544 -0
- data/spec/prawn/graphics/blend_mode_spec.rb +63 -0
- data/spec/prawn/graphics/transparency_spec.rb +81 -0
- data/spec/prawn/graphics_spec.rb +872 -0
- data/spec/prawn/graphics_stroke_styles_spec.rb +229 -0
- data/spec/prawn/image_handler_spec.rb +53 -0
- data/spec/prawn/images/jpg_spec.rb +20 -0
- data/spec/prawn/images/png_spec.rb +283 -0
- data/spec/prawn/images_spec.rb +229 -0
- data/spec/prawn/measurements_extensions_spec.rb +24 -0
- data/spec/prawn/outline_spec.rb +512 -0
- data/spec/prawn/repeater_spec.rb +166 -0
- data/spec/prawn/soft_mask_spec.rb +74 -0
- data/spec/prawn/stamp_spec.rb +173 -0
- data/spec/prawn/text/box_spec.rb +1110 -0
- data/spec/prawn/text/formatted/arranger_spec.rb +466 -0
- data/spec/prawn/text/formatted/box_spec.rb +849 -0
- data/spec/prawn/text/formatted/fragment_spec.rb +343 -0
- data/spec/prawn/text/formatted/line_wrap_spec.rb +495 -0
- data/spec/prawn/text/formatted/parser_spec.rb +697 -0
- data/spec/prawn/text_draw_text_spec.rb +150 -0
- data/spec/prawn/text_rendering_mode_spec.rb +48 -0
- data/spec/prawn/text_spacing_spec.rb +95 -0
- data/spec/prawn/text_spec.rb +603 -0
- data/spec/prawn/text_with_inline_formatting_spec.rb +35 -0
- data/spec/prawn/transformation_stack_spec.rb +66 -0
- data/spec/prawn/view_spec.rb +63 -0
- data/spec/prawn_manual_spec.rb +35 -0
- data/spec/spec_helper.rb +22 -21
- data.tar.gz.sig +0 -0
- metadata +168 -307
- metadata.gz.sig +0 -0
- data/README.md +0 -109
- data/data/encodings/win_ansi.txt +0 -29
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.dat +0 -0
- data/data/images/16bit.png +0 -0
- data/data/images/arrow.png +0 -0
- data/data/images/arrow2.png +0 -0
- data/data/images/barcode_issue.png +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.dat +0 -0
- data/data/images/dice.png +0 -0
- data/data/images/dice_interlaced.png +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/letterhead.jpg +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/page_white_text.png +0 -0
- data/data/images/pigs.jpg +0 -0
- data/data/images/prawn.png +0 -0
- data/data/images/ruport.png +0 -0
- data/data/images/ruport_data.dat +0 -0
- data/data/images/ruport_transparent.png +0 -0
- data/data/images/ruport_type0.png +0 -0
- data/data/images/stef.jpg +0 -0
- data/data/images/tru256.bmp +0 -0
- data/data/images/web-links.dat +0 -1
- data/data/images/web-links.png +0 -0
- data/data/pdfs/complex_template.pdf +0 -0
- data/data/pdfs/contains_ttf_font.pdf +0 -0
- data/data/pdfs/encrypted.pdf +0 -0
- data/data/pdfs/form.pdf +1 -819
- data/data/pdfs/hexagon.pdf +0 -61
- data/data/pdfs/indirect_reference.pdf +0 -86
- data/data/pdfs/multipage_template.pdf +0 -127
- data/data/pdfs/nested_pages.pdf +0 -118
- data/data/pdfs/page_without_mediabox.pdf +0 -193
- data/data/pdfs/resources_as_indirect_object.pdf +0 -83
- data/data/pdfs/two_hexagons.pdf +0 -90
- data/data/pdfs/version_1_6.pdf +0 -61
- data/data/shift_jis_text.txt +0 -1
- data/lib/pdf/core/annotations.rb +0 -60
- data/lib/pdf/core/byte_string.rb +0 -9
- data/lib/pdf/core/destinations.rb +0 -90
- data/lib/pdf/core/document_state.rb +0 -78
- data/lib/pdf/core/filter_list.rb +0 -51
- data/lib/pdf/core/filters.rb +0 -36
- data/lib/pdf/core/graphics_state.rb +0 -68
- data/lib/pdf/core/literal_string.rb +0 -16
- data/lib/pdf/core/name_tree.rb +0 -177
- data/lib/pdf/core/object_store.rb +0 -320
- data/lib/pdf/core/outline.rb +0 -315
- data/lib/pdf/core/page.rb +0 -212
- data/lib/pdf/core/page_geometry.rb +0 -126
- data/lib/pdf/core/pdf_object.rb +0 -124
- data/lib/pdf/core/reference.rb +0 -103
- data/lib/pdf/core/stream.rb +0 -98
- data/lib/pdf/core/text.rb +0 -275
- data/lib/pdf/core.rb +0 -35
- data/lib/prawn/compatibility.rb +0 -91
- data/lib/prawn/document/graphics_state.rb +0 -73
- data/lib/prawn/document/snapshot.rb +0 -89
- data/lib/prawn/font/afm.rb +0 -203
- data/lib/prawn/layout.rb +0 -20
- data/lib/prawn/table/cell/image.rb +0 -70
- data/lib/prawn/table/cell/in_table.rb +0 -27
- data/lib/prawn/table/cell/span_dummy.rb +0 -92
- data/lib/prawn/table/cell/subtable.rb +0 -65
- data/lib/prawn/table/cell/text.rb +0 -153
- data/lib/prawn/table/cell.rb +0 -770
- data/lib/prawn/table/cells.rb +0 -295
- data/lib/prawn/table.rb +0 -643
- data/manual/example_file.rb +0 -116
- data/manual/example_package.rb +0 -53
- data/manual/example_section.rb +0 -46
- data/manual/manual/cover.rb +0 -35
- data/manual/manual/foreword.rb +0 -85
- data/manual/manual/manual.rb +0 -35
- data/manual/syntax_highlight.rb +0 -52
- data/manual/table/basic_block.rb +0 -53
- data/manual/table/before_rendering_page.rb +0 -26
- data/manual/table/cell_border_lines.rb +0 -24
- data/manual/table/cell_borders_and_bg.rb +0 -31
- data/manual/table/cell_dimensions.rb +0 -30
- data/manual/table/cell_text.rb +0 -38
- data/manual/table/column_widths.rb +0 -30
- data/manual/table/content_and_subtables.rb +0 -39
- data/manual/table/creation.rb +0 -27
- data/manual/table/filtering.rb +0 -36
- data/manual/table/flow_and_header.rb +0 -17
- data/manual/table/image_cells.rb +0 -33
- data/manual/table/position.rb +0 -29
- data/manual/table/row_colors.rb +0 -20
- data/manual/table/span.rb +0 -30
- data/manual/table/style.rb +0 -22
- data/manual/table/table.rb +0 -52
- data/manual/table/width.rb +0 -27
- data/manual/templates/full_template.rb +0 -25
- data/manual/templates/page_template.rb +0 -48
- data/manual/templates/templates.rb +0 -27
- data/manual/text/group.rb +0 -29
- data/spec/acceptance/png.rb +0 -23
- data/spec/annotations_spec.rb +0 -74
- data/spec/bounding_box_spec.rb +0 -493
- data/spec/cell_spec.rb +0 -628
- data/spec/column_box_spec.rb +0 -33
- data/spec/destinations_spec.rb +0 -15
- data/spec/document_spec.rb +0 -761
- data/spec/extensions/mocha.rb +0 -44
- data/spec/filters_spec.rb +0 -34
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/font_spec.rb +0 -464
- data/spec/formatted_text_arranger_spec.rb +0 -421
- data/spec/formatted_text_box_spec.rb +0 -650
- data/spec/formatted_text_fragment_spec.rb +0 -298
- data/spec/graphics_spec.rb +0 -651
- data/spec/grid_spec.rb +0 -85
- data/spec/image_handler_spec.rb +0 -42
- data/spec/images_spec.rb +0 -157
- data/spec/inline_formatted_text_parser_spec.rb +0 -564
- data/spec/jpg_spec.rb +0 -25
- data/spec/line_wrap_spec.rb +0 -333
- data/spec/measurement_units_spec.rb +0 -23
- data/spec/name_tree_spec.rb +0 -112
- data/spec/object_store_spec.rb +0 -170
- data/spec/outline_spec.rb +0 -448
- data/spec/pdf_object_spec.rb +0 -172
- data/spec/png_spec.rb +0 -240
- data/spec/reference_spec.rb +0 -82
- data/spec/repeater_spec.rb +0 -158
- data/spec/security_spec.rb +0 -158
- data/spec/snapshot_spec.rb +0 -186
- data/spec/soft_mask_spec.rb +0 -117
- data/spec/span_spec.rb +0 -44
- data/spec/stamp_spec.rb +0 -158
- data/spec/stream_spec.rb +0 -58
- data/spec/stroke_styles_spec.rb +0 -211
- data/spec/table/span_dummy_spec.rb +0 -17
- data/spec/table_spec.rb +0 -1355
- data/spec/template_spec.rb +0 -351
- data/spec/text_at_spec.rb +0 -130
- data/spec/text_box_spec.rb +0 -1030
- data/spec/text_rendering_mode_spec.rb +0 -45
- data/spec/text_spacing_spec.rb +0 -93
- data/spec/text_spec.rb +0 -425
- data/spec/text_with_inline_formatting_spec.rb +0 -35
- data/spec/transparency_spec.rb +0 -89
data/lib/prawn/images/png.rb
CHANGED
@@ -1,5 +1,7 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
2
|
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
3
5
|
# png.rb : Extracts the data from a PNG that is needed for embedding
|
4
6
|
#
|
5
7
|
# Based on some similar code in PDF::Writer by Austin Ziegler
|
@@ -9,14 +11,14 @@
|
|
9
11
|
# This is free software. Please see the LICENSE and COPYING files for details.
|
10
12
|
|
11
13
|
require 'stringio'
|
12
|
-
require 'enumerator'
|
13
|
-
|
14
14
|
module Prawn
|
15
15
|
module Images
|
16
16
|
# A convenience class that wraps the logic for extracting the parts
|
17
17
|
# of a PNG image that we need to embed them in a PDF
|
18
18
|
#
|
19
19
|
class PNG < Image
|
20
|
+
# @group Extension API
|
21
|
+
|
20
22
|
attr_reader :palette, :img_data, :transparency
|
21
23
|
attr_reader :width, :height, :bits
|
22
24
|
attr_reader :color_type, :compression_method, :filter_method
|
@@ -24,7 +26,7 @@ module Prawn
|
|
24
26
|
attr_accessor :scaled_width, :scaled_height
|
25
27
|
|
26
28
|
def self.can_render?(image_blob)
|
27
|
-
image_blob[0, 8].unpack(
|
29
|
+
image_blob[0, 8].unpack('C*') == [137, 80, 78, 71, 13, 10, 26, 10]
|
28
30
|
end
|
29
31
|
|
30
32
|
# Process a new PNG image
|
@@ -32,30 +34,31 @@ module Prawn
|
|
32
34
|
# <tt>data</tt>:: A binary string of PNG data
|
33
35
|
#
|
34
36
|
def initialize(data)
|
37
|
+
super()
|
35
38
|
data = StringIO.new(data.dup)
|
36
39
|
|
37
|
-
data.read(8)
|
40
|
+
data.read(8) # Skip the default header
|
38
41
|
|
39
|
-
@palette
|
40
|
-
@img_data =
|
42
|
+
@palette = +''
|
43
|
+
@img_data = +''
|
41
44
|
@transparency = {}
|
42
45
|
|
43
46
|
loop do
|
44
|
-
chunk_size
|
45
|
-
section
|
47
|
+
chunk_size = data.read(4).unpack1('N')
|
48
|
+
section = data.read(4)
|
46
49
|
case section
|
47
50
|
when 'IHDR'
|
48
51
|
# we can grab other interesting values from here (like width,
|
49
52
|
# height, etc)
|
50
|
-
values = data.read(chunk_size).unpack(
|
53
|
+
values = data.read(chunk_size).unpack('NNCCCCC')
|
51
54
|
|
52
|
-
@width
|
53
|
-
@height
|
54
|
-
@bits
|
55
|
-
@color_type
|
55
|
+
@width = values[0]
|
56
|
+
@height = values[1]
|
57
|
+
@bits = values[2]
|
58
|
+
@color_type = values[3]
|
56
59
|
@compression_method = values[4]
|
57
|
-
@filter_method
|
58
|
-
@interlace_method
|
60
|
+
@filter_method = values[5]
|
61
|
+
@interlace_method = values[6]
|
59
62
|
when 'PLTE'
|
60
63
|
@palette << data.read(chunk_size)
|
61
64
|
when 'IDAT'
|
@@ -66,21 +69,15 @@ module Prawn
|
|
66
69
|
@transparency = {}
|
67
70
|
case @color_type
|
68
71
|
when 3
|
69
|
-
|
70
|
-
# the palette index in the PLTE ("palette") chunk up until the
|
71
|
-
# last non-opaque entry. Set up an array, stretching over all
|
72
|
-
# palette entries which will be 0 (opaque) or 1 (transparent).
|
73
|
-
@transparency[:indexed] = data.read(chunk_size).unpack("C*")
|
74
|
-
short = 255 - @transparency[:indexed].size
|
75
|
-
@transparency[:indexed] += ([255] * short) if short > 0
|
72
|
+
@transparency[:palette] = data.read(chunk_size).unpack('C*')
|
76
73
|
when 0
|
77
74
|
# Greyscale. Corresponding to entries in the PLTE chunk.
|
78
75
|
# Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
|
79
|
-
grayval = data.read(chunk_size).
|
76
|
+
grayval = data.read(chunk_size).unpack1('n')
|
80
77
|
@transparency[:grayscale] = grayval
|
81
78
|
when 2
|
82
79
|
# True colour with proper alpha channel.
|
83
|
-
@transparency[:rgb] = data.read(chunk_size).unpack(
|
80
|
+
@transparency[:rgb] = data.read(chunk_size).unpack('nnn')
|
84
81
|
end
|
85
82
|
when 'IEND'
|
86
83
|
# we've got everything we need, exit the loop
|
@@ -90,7 +87,7 @@ module Prawn
|
|
90
87
|
data.seek(data.pos + chunk_size)
|
91
88
|
end
|
92
89
|
|
93
|
-
data.read(4)
|
90
|
+
data.read(4) # Skip the CRC
|
94
91
|
end
|
95
92
|
|
96
93
|
@img_data = Zlib::Inflate.inflate(@img_data)
|
@@ -99,21 +96,11 @@ module Prawn
|
|
99
96
|
# number of color components to each pixel
|
100
97
|
#
|
101
98
|
def colors
|
102
|
-
case
|
99
|
+
case color_type
|
103
100
|
when 0, 3, 4
|
104
|
-
|
101
|
+
1
|
105
102
|
when 2, 6
|
106
|
-
|
107
|
-
end
|
108
|
-
end
|
109
|
-
|
110
|
-
# number of bits used per pixel
|
111
|
-
#
|
112
|
-
def pixel_bitlength
|
113
|
-
if alpha_channel?
|
114
|
-
self.bits * (self.colors + 1)
|
115
|
-
else
|
116
|
-
self.bits * self.colors
|
103
|
+
3
|
117
104
|
end
|
118
105
|
end
|
119
106
|
|
@@ -121,18 +108,20 @@ module Prawn
|
|
121
108
|
# where it's required.
|
122
109
|
#
|
123
110
|
def split_alpha_channel!
|
124
|
-
|
111
|
+
if alpha_channel?
|
112
|
+
if color_type == 3
|
113
|
+
generate_alpha_channel
|
114
|
+
else
|
115
|
+
split_image_data
|
116
|
+
end
|
117
|
+
end
|
125
118
|
end
|
126
119
|
|
127
120
|
def alpha_channel?
|
128
|
-
|
129
|
-
|
121
|
+
return true if color_type == 4 || color_type == 6
|
122
|
+
return @transparency.any? if color_type == 3
|
130
123
|
|
131
|
-
|
132
|
-
# byte (least significant)
|
133
|
-
#
|
134
|
-
def alpha_channel_bits
|
135
|
-
8
|
124
|
+
false
|
136
125
|
end
|
137
126
|
|
138
127
|
# Build a PDF object representing this image in +document+, and return
|
@@ -170,28 +159,24 @@ module Prawn
|
|
170
159
|
|
171
160
|
# build the image dict
|
172
161
|
obj = document.ref!(
|
173
|
-
:
|
174
|
-
:
|
175
|
-
:
|
176
|
-
:
|
177
|
-
:
|
162
|
+
Type: :XObject,
|
163
|
+
Subtype: :Image,
|
164
|
+
Height: height,
|
165
|
+
Width: width,
|
166
|
+
BitsPerComponent: bits
|
178
167
|
)
|
179
168
|
|
180
169
|
# append the actual image data to the object as a stream
|
181
170
|
obj << img_data
|
182
171
|
|
183
|
-
|
184
|
-
|
185
|
-
|
186
|
-
|
187
|
-
:
|
188
|
-
|
189
|
-
:Colors => colors,
|
190
|
-
:BitsPerComponent => bits,
|
191
|
-
:Columns => width
|
192
|
-
}
|
172
|
+
obj.stream.filters << {
|
173
|
+
FlateDecode: {
|
174
|
+
Predictor: 15,
|
175
|
+
Colors: colors,
|
176
|
+
BitsPerComponent: bits,
|
177
|
+
Columns: width
|
193
178
|
}
|
194
|
-
|
179
|
+
}
|
195
180
|
|
196
181
|
# sort out the colours of the image
|
197
182
|
if palette.empty?
|
@@ -202,10 +187,12 @@ module Prawn
|
|
202
187
|
palette_obj << palette
|
203
188
|
|
204
189
|
# build the color space array for the image
|
205
|
-
obj.data[:ColorSpace] = [
|
206
|
-
|
207
|
-
|
208
|
-
|
190
|
+
obj.data[:ColorSpace] = [
|
191
|
+
:Indexed,
|
192
|
+
:DeviceRGB,
|
193
|
+
(palette.size / 3) - 1,
|
194
|
+
palette_obj
|
195
|
+
]
|
209
196
|
end
|
210
197
|
|
211
198
|
# *************************************
|
@@ -226,29 +213,33 @@ module Prawn
|
|
226
213
|
# - An array with N elements, where N is two times the number of color
|
227
214
|
# components.
|
228
215
|
rgb = transparency[:rgb]
|
229
|
-
obj.data[:Mask] = rgb.
|
230
|
-
elsif transparency[:indexed]
|
231
|
-
# TODO: broken. I was attempting to us Color Key Masking, but I think
|
232
|
-
# we need to construct an SMask i think. Maybe do it inside
|
233
|
-
# the PNG class, and store it in alpha_channel
|
234
|
-
#obj.data[:Mask] = transparency[:indexed]
|
216
|
+
obj.data[:Mask] = rgb.map { |x| [x, x] }.flatten
|
235
217
|
end
|
236
218
|
|
237
|
-
# For PNG color types 4 and 6, the transparency data is stored as
|
238
|
-
# channel mixed in with the main image data. The PNG class
|
239
|
-
# it out for us and makes it available via the alpha_channel
|
219
|
+
# For PNG color types 4 and 6, the transparency data is stored as
|
220
|
+
# a alpha channel mixed in with the main image data. The PNG class
|
221
|
+
# seperates it out for us and makes it available via the alpha_channel
|
222
|
+
# attribute
|
240
223
|
if alpha_channel?
|
241
224
|
smask_obj = document.ref!(
|
242
|
-
:
|
243
|
-
:
|
244
|
-
:
|
245
|
-
:
|
246
|
-
:
|
247
|
-
:
|
248
|
-
:
|
225
|
+
Type: :XObject,
|
226
|
+
Subtype: :Image,
|
227
|
+
Height: height,
|
228
|
+
Width: width,
|
229
|
+
BitsPerComponent: bits,
|
230
|
+
ColorSpace: :DeviceGray,
|
231
|
+
Decode: [0, 1]
|
249
232
|
)
|
250
233
|
smask_obj.stream << alpha_channel
|
251
|
-
|
234
|
+
|
235
|
+
smask_obj.stream.filters << {
|
236
|
+
FlateDecode: {
|
237
|
+
Predictor: 15,
|
238
|
+
Colors: 1,
|
239
|
+
BitsPerComponent: bits,
|
240
|
+
Columns: width
|
241
|
+
}
|
242
|
+
}
|
252
243
|
obj.data[:SMask] = smask_obj
|
253
244
|
end
|
254
245
|
|
@@ -270,97 +261,69 @@ module Prawn
|
|
270
261
|
|
271
262
|
private
|
272
263
|
|
273
|
-
def
|
274
|
-
|
275
|
-
|
276
|
-
@img_data = ""
|
277
|
-
@alpha_channel = ""
|
278
|
-
|
279
|
-
pixel_bytes = pixel_bitlength / 8
|
280
|
-
scanline_length = pixel_bytes * self.width + 1
|
281
|
-
row = 0
|
282
|
-
pixels = []
|
283
|
-
row_data = [] # reused for each row of the image
|
284
|
-
paeth, pa, pb, pc = nil
|
285
|
-
|
286
|
-
data.bytes.each do |byte|
|
287
|
-
# accumulate a whole scanline of bytes, and then process it all at once
|
288
|
-
# we could do this with Enumerable#each_slice, but it allocates memory,
|
289
|
-
# and we are trying to avoid that
|
290
|
-
row_data << byte
|
291
|
-
next if row_data.length < scanline_length
|
292
|
-
|
293
|
-
filter = row_data.shift
|
294
|
-
case filter
|
295
|
-
when 0 # None
|
296
|
-
when 1 # Sub
|
297
|
-
row_data.each_with_index do |row_byte, index|
|
298
|
-
left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
|
299
|
-
row_data[index] = (row_byte + left) % 256
|
300
|
-
end
|
301
|
-
when 2 # Up
|
302
|
-
row_data.each_with_index do |row_byte, index|
|
303
|
-
col = (index / pixel_bytes).floor
|
304
|
-
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
|
305
|
-
row_data[index] = (upper + row_byte) % 256
|
306
|
-
end
|
307
|
-
when 3 # Average
|
308
|
-
row_data.each_with_index do |row_byte, index|
|
309
|
-
col = (index / pixel_bytes).floor
|
310
|
-
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
|
311
|
-
left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
|
264
|
+
def split_image_data
|
265
|
+
alpha_bytes = bits / 8
|
266
|
+
color_bytes = colors * bits / 8
|
312
267
|
|
313
|
-
|
314
|
-
|
315
|
-
|
316
|
-
|
317
|
-
|
318
|
-
|
319
|
-
|
320
|
-
|
321
|
-
|
322
|
-
|
323
|
-
|
324
|
-
|
325
|
-
|
326
|
-
|
327
|
-
|
328
|
-
|
329
|
-
|
330
|
-
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
left
|
336
|
-
elsif pb <= pc
|
337
|
-
upper
|
338
|
-
else
|
339
|
-
upper_left
|
340
|
-
end
|
341
|
-
|
342
|
-
row_data[index] = (row_byte + paeth) % 256
|
343
|
-
end
|
344
|
-
else
|
345
|
-
raise ArgumentError, "Invalid filter algorithm #{filter}"
|
346
|
-
end
|
268
|
+
scanline_length = (color_bytes + alpha_bytes) * width + 1
|
269
|
+
scanlines = @img_data.bytesize / scanline_length
|
270
|
+
pixels = width * height
|
271
|
+
|
272
|
+
data = StringIO.new(@img_data)
|
273
|
+
data.binmode
|
274
|
+
|
275
|
+
color_data = [0x00].pack('C') * (pixels * color_bytes + scanlines)
|
276
|
+
color = StringIO.new(color_data)
|
277
|
+
color.binmode
|
278
|
+
|
279
|
+
@alpha_channel = [0x00].pack('C') * (pixels * alpha_bytes + scanlines)
|
280
|
+
alpha = StringIO.new(@alpha_channel)
|
281
|
+
alpha.binmode
|
282
|
+
|
283
|
+
scanlines.times do |line|
|
284
|
+
data.seek(line * scanline_length)
|
285
|
+
|
286
|
+
filter = data.getbyte
|
287
|
+
|
288
|
+
color.putc filter
|
289
|
+
alpha.putc filter
|
347
290
|
|
348
|
-
|
349
|
-
|
350
|
-
|
291
|
+
width.times do
|
292
|
+
color.write data.read(color_bytes)
|
293
|
+
alpha.write data.read(alpha_bytes)
|
351
294
|
end
|
352
|
-
pixels << s
|
353
|
-
row += 1
|
354
|
-
row_data.clear
|
355
295
|
end
|
356
296
|
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
|
297
|
+
@img_data = color_data
|
298
|
+
end
|
299
|
+
|
300
|
+
def generate_alpha_channel
|
301
|
+
alpha_palette = Hash.new(0xff)
|
302
|
+
0.upto(palette.bytesize / 3) do |n|
|
303
|
+
alpha_palette[n] = @transparency[:palette][n] || 0xff
|
304
|
+
end
|
305
|
+
|
306
|
+
scanline_length = width + 1
|
307
|
+
scanlines = @img_data.bytesize / scanline_length
|
308
|
+
pixels = width * height
|
309
|
+
|
310
|
+
data = StringIO.new(@img_data)
|
311
|
+
data.binmode
|
312
|
+
|
313
|
+
@alpha_channel = [0x00].pack('C') * (pixels + scanlines)
|
314
|
+
alpha = StringIO.new(@alpha_channel)
|
315
|
+
alpha.binmode
|
316
|
+
|
317
|
+
scanlines.times do |line|
|
318
|
+
data.seek(line * scanline_length)
|
319
|
+
|
320
|
+
filter = data.getbyte
|
321
|
+
|
322
|
+
alpha.putc filter
|
323
|
+
|
324
|
+
width.times do
|
325
|
+
color = data.read(1).unpack1('C')
|
326
|
+
alpha.putc alpha_palette[color]
|
364
327
|
end
|
365
328
|
end
|
366
329
|
end
|
data/lib/prawn/images.rb
CHANGED
@@ -1,4 +1,7 @@
|
|
1
1
|
# encoding: ASCII-8BIT
|
2
|
+
|
3
|
+
# frozen_string_literal: true
|
4
|
+
|
2
5
|
# images.rb : Implements PDF image embedding
|
3
6
|
#
|
4
7
|
# Copyright April 2008, James Healy, Gregory Brown. All Rights Reserved.
|
@@ -9,28 +12,27 @@ require 'digest/sha1'
|
|
9
12
|
require 'pathname'
|
10
13
|
|
11
14
|
module Prawn
|
12
|
-
|
13
15
|
module Images
|
16
|
+
# @group Stable API
|
17
|
+
|
14
18
|
# Add the image at filename to the current page. Currently only
|
15
|
-
# JPG and PNG files are supported.
|
16
|
-
#
|
17
|
-
# NOTE: Prawn is very slow at rendering PNGs with alpha channels, and this
|
18
|
-
# uses a lot of RAM. The workaround for those who don't mind installing
|
19
|
-
# RMagick is to use:
|
20
|
-
#
|
21
|
-
# http://github.com/amberbit/prawn-fast-png
|
19
|
+
# JPG and PNG files are supported. (Note that processing PNG
|
20
|
+
# images with alpha channels can be processor and memory intensive.)
|
22
21
|
#
|
23
22
|
# Arguments:
|
24
|
-
# <tt>file</tt>:: path to file or an object that responds to #read
|
23
|
+
# <tt>file</tt>:: path to file or an object that responds to #read and
|
24
|
+
# #rewind
|
25
25
|
#
|
26
26
|
# Options:
|
27
|
-
# <tt>:at</tt>:: an array [x,y] with the location of the top left corner of
|
27
|
+
# <tt>:at</tt>:: an array [x,y] with the location of the top left corner of
|
28
|
+
# the image.
|
28
29
|
# <tt>:position</tt>:: One of (:left, :center, :right) or an x-offset
|
29
|
-
# <tt>:vposition</tt>:: One of (:top, :center, :
|
30
|
+
# <tt>:vposition</tt>:: One of (:top, :center, :bottom) or an y-offset
|
30
31
|
# <tt>:height</tt>:: the height of the image [actual height of the image]
|
31
32
|
# <tt>:width</tt>:: the width of the image [actual width of the image]
|
32
33
|
# <tt>:scale</tt>:: scale the dimensions of the image proportionally
|
33
|
-
# <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit
|
34
|
+
# <tt>:fit</tt>:: scale the dimensions of the image proportionally to fit
|
35
|
+
# inside [width,height]
|
34
36
|
#
|
35
37
|
# Prawn::Document.generate("image2.pdf", :page_layout => :landscape) do
|
36
38
|
# pigs = "#{Prawn::DATADIR}/images/pigs.jpg"
|
@@ -56,16 +58,18 @@ module Prawn
|
|
56
58
|
# require "open-uri"
|
57
59
|
#
|
58
60
|
# Prawn::Document.generate("remote_images.pdf") do
|
59
|
-
# image open("http://
|
61
|
+
# image open("http://prawnpdf.org/media/prawn_logo.png")
|
60
62
|
# end
|
61
63
|
#
|
62
64
|
# This method returns an image info object which can be used to check the
|
63
65
|
# dimensions of an image object if needed.
|
64
66
|
# (See also: Prawn::Images::PNG , Prawn::Images::JPG)
|
65
67
|
#
|
66
|
-
def image(file, options={})
|
67
|
-
Prawn.verify_options
|
68
|
-
|
68
|
+
def image(file, options = {})
|
69
|
+
Prawn.verify_options(
|
70
|
+
%i[at position vposition height width scale fit],
|
71
|
+
options
|
72
|
+
)
|
69
73
|
|
70
74
|
pdf_obj, info = build_image_object(file)
|
71
75
|
embed_image(pdf_obj, info, options)
|
@@ -76,9 +80,9 @@ module Prawn
|
|
76
80
|
# Builds an info object (Prawn::Images::*) and a PDF reference representing
|
77
81
|
# the given image. Return a pair: [pdf_obj, info].
|
78
82
|
#
|
83
|
+
# @private
|
79
84
|
def build_image_object(file)
|
80
|
-
|
81
|
-
image_content = io.read
|
85
|
+
image_content = verify_and_read_image(file)
|
82
86
|
image_sha1 = Digest::SHA1.hexdigest(image_content)
|
83
87
|
|
84
88
|
# if this image has already been embedded, just reuse it
|
@@ -90,11 +94,13 @@ module Prawn
|
|
90
94
|
info = Prawn.image_handler.find(image_content).new(image_content)
|
91
95
|
|
92
96
|
# Bump PDF version if the image requires it
|
93
|
-
|
97
|
+
if info.respond_to?(:min_pdf_version)
|
98
|
+
renderer.min_version(info.min_pdf_version)
|
99
|
+
end
|
94
100
|
|
95
101
|
# Add the image to the PDF and register it in case we see it again.
|
96
102
|
image_obj = info.build_pdf_object(self)
|
97
|
-
image_registry[image_sha1] = {:
|
103
|
+
image_registry[image_sha1] = { obj: image_obj, info: info }
|
98
104
|
end
|
99
105
|
|
100
106
|
[image_obj, info]
|
@@ -105,30 +111,30 @@ module Prawn
|
|
105
111
|
# build_image_object), embed the image according to the <tt>options</tt>
|
106
112
|
# given.
|
107
113
|
#
|
114
|
+
# @private
|
108
115
|
def embed_image(pdf_obj, info, options)
|
109
116
|
# find where the image will be placed and how big it will be
|
110
|
-
w,h = info.calc_image_dimensions(options)
|
117
|
+
w, h = info.calc_image_dimensions(options)
|
111
118
|
|
112
119
|
if options[:at]
|
113
|
-
x,y = map_to_absolute(options[:at])
|
120
|
+
x, y = map_to_absolute(options[:at])
|
114
121
|
else
|
115
|
-
x,y = image_position(w,h,options)
|
122
|
+
x, y = image_position(w, h, options)
|
116
123
|
move_text_position h
|
117
124
|
end
|
118
125
|
|
119
126
|
# add a reference to the image object to the current page
|
120
127
|
# resource list and give it a label
|
121
128
|
label = "I#{next_image_id}"
|
122
|
-
state.page.xobjects
|
129
|
+
state.page.xobjects[label] = pdf_obj
|
123
130
|
|
124
|
-
|
125
|
-
|
126
|
-
add_content instruct % [ w, h, x, y - h, label ]
|
131
|
+
cm_params = PDF::Core.real_params([w, 0, 0, h, x, y - h])
|
132
|
+
renderer.add_content("\nq\n#{cm_params} cm\n/#{label} Do\nQ")
|
127
133
|
end
|
128
134
|
|
129
135
|
private
|
130
136
|
|
131
|
-
def
|
137
|
+
def verify_and_read_image(io_or_path)
|
132
138
|
# File or IO
|
133
139
|
if io_or_path.respond_to?(:rewind)
|
134
140
|
io = io_or_path
|
@@ -138,54 +144,56 @@ module Prawn
|
|
138
144
|
# read the file as binary so the size is calculated correctly
|
139
145
|
# guard binmode because some objects acting io-like don't implement it
|
140
146
|
io.binmode if io.respond_to?(:binmode)
|
141
|
-
return io
|
147
|
+
return io.read
|
142
148
|
end
|
143
149
|
# String or Pathname
|
144
150
|
io_or_path = Pathname.new(io_or_path)
|
145
151
|
raise ArgumentError, "#{io_or_path} not found" unless io_or_path.file?
|
146
|
-
|
147
|
-
|
152
|
+
|
153
|
+
io_or_path.binread
|
148
154
|
end
|
149
155
|
|
150
|
-
def image_position(
|
156
|
+
def image_position(width, height, options)
|
151
157
|
options[:position] ||= :left
|
152
158
|
|
153
|
-
y =
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
159
|
+
y =
|
160
|
+
case options[:vposition]
|
161
|
+
when :top
|
162
|
+
bounds.absolute_top
|
163
|
+
when :center
|
164
|
+
bounds.absolute_top - (bounds.height - height) / 2.0
|
165
|
+
when :bottom
|
166
|
+
bounds.absolute_bottom + height
|
167
|
+
when Numeric
|
168
|
+
bounds.absolute_top - options[:vposition]
|
169
|
+
else
|
170
|
+
determine_y_with_page_flow(height)
|
171
|
+
end
|
172
|
+
|
173
|
+
x =
|
174
|
+
case options[:position]
|
175
|
+
when :left
|
176
|
+
bounds.left_side
|
177
|
+
when :center
|
178
|
+
bounds.left_side + (bounds.width - width) / 2.0
|
179
|
+
when :right
|
180
|
+
bounds.right_side - width
|
181
|
+
when Numeric
|
182
|
+
options[:position] + bounds.left_side
|
183
|
+
end
|
184
|
+
|
185
|
+
[x, y]
|
178
186
|
end
|
179
187
|
|
180
|
-
def determine_y_with_page_flow(
|
181
|
-
if overruns_page?(
|
188
|
+
def determine_y_with_page_flow(height)
|
189
|
+
if overruns_page?(height)
|
182
190
|
bounds.move_past_bottom
|
183
191
|
end
|
184
|
-
|
192
|
+
y
|
185
193
|
end
|
186
194
|
|
187
|
-
def overruns_page?(
|
188
|
-
(
|
195
|
+
def overruns_page?(height)
|
196
|
+
(y - height) < reference_bounds.absolute_bottom
|
189
197
|
end
|
190
198
|
|
191
199
|
def image_registry
|