prawn 0.15.0 → 1.0.0.rc1
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.
- data/COPYING +2 -2
- data/LICENSE +1 -1
- data/README.md +96 -0
- data/Rakefile +27 -30
- data/data/fonts/Action Man.dfont +0 -0
- data/data/fonts/Activa.ttf +0 -0
- data/data/fonts/Chalkboard.ttf +0 -0
- data/data/fonts/DejaVuSans.ttf +0 -0
- data/data/fonts/Dustismo_Roman.ttf +0 -0
- data/data/fonts/comicsans.ttf +0 -0
- data/data/fonts/gkai00mp.ttf +0 -0
- data/data/images/16bit.alpha +0 -0
- data/data/images/16bit.dat +0 -0
- data/data/images/dice.alpha +0 -0
- data/data/images/dice.dat +0 -0
- data/data/images/page_white_text.alpha +0 -0
- data/data/images/page_white_text.dat +0 -0
- data/data/images/rails.dat +0 -0
- data/data/images/rails.png +0 -0
- data/data/pdfs/nested_pages.pdf +13 -13
- data/lib/prawn.rb +21 -85
- data/lib/prawn/compatibility.rb +51 -0
- data/lib/prawn/core.rb +85 -0
- data/lib/prawn/core/annotations.rb +61 -0
- data/lib/prawn/core/byte_string.rb +9 -0
- data/lib/prawn/core/destinations.rb +90 -0
- data/lib/prawn/core/document_state.rb +78 -0
- data/lib/prawn/core/literal_string.rb +16 -0
- data/lib/prawn/core/name_tree.rb +177 -0
- data/lib/prawn/core/object_store.rb +264 -0
- data/lib/prawn/core/page.rb +215 -0
- data/lib/prawn/core/pdf_object.rb +108 -0
- data/lib/prawn/core/reference.rb +115 -0
- data/lib/prawn/core/text.rb +268 -0
- data/lib/prawn/core/text/formatted/arranger.rb +294 -0
- data/lib/prawn/core/text/formatted/line_wrap.rb +273 -0
- data/lib/prawn/core/text/formatted/wrap.rb +153 -0
- data/lib/prawn/document.rb +122 -155
- data/lib/prawn/document/bounding_box.rb +7 -36
- data/lib/prawn/document/column_box.rb +10 -38
- data/lib/prawn/document/graphics_state.rb +74 -11
- data/lib/prawn/document/internals.rb +23 -24
- data/lib/prawn/document/page_geometry.rb +136 -0
- data/lib/prawn/document/snapshot.rb +6 -7
- data/lib/prawn/document/span.rb +10 -12
- data/lib/prawn/encoding.rb +10 -9
- data/lib/prawn/errors.rb +30 -15
- data/lib/prawn/font.rb +104 -136
- data/lib/prawn/font/afm.rb +44 -46
- data/lib/prawn/font/dfont.rb +3 -4
- data/lib/prawn/font/ttf.rb +50 -31
- data/lib/prawn/graphics.rb +57 -302
- data/lib/prawn/graphics/cap_style.rb +3 -4
- data/lib/prawn/graphics/color.rb +5 -13
- data/lib/prawn/graphics/dash.rb +31 -53
- data/lib/prawn/graphics/gradient.rb +84 -0
- data/lib/prawn/graphics/join_style.rb +7 -9
- data/lib/prawn/graphics/transformation.rb +9 -10
- data/lib/prawn/graphics/transparency.rb +1 -3
- data/lib/prawn/images.rb +59 -69
- data/lib/prawn/images/image.rb +22 -6
- data/lib/prawn/images/jpg.rb +14 -20
- data/lib/prawn/images/png.rb +118 -61
- data/lib/prawn/layout.rb +15 -10
- data/lib/prawn/layout/grid.rb +54 -66
- data/lib/prawn/measurement_extensions.rb +6 -10
- data/lib/prawn/measurements.rb +21 -27
- data/lib/prawn/outline.rb +308 -6
- data/lib/prawn/repeater.rb +8 -10
- data/lib/prawn/security.rb +33 -55
- data/lib/prawn/security/arcfour.rb +0 -1
- data/lib/prawn/stamp.rb +3 -5
- data/lib/prawn/table.rb +60 -188
- data/lib/prawn/table/cell.rb +44 -272
- data/lib/prawn/table/cell/image.rb +3 -2
- data/lib/prawn/table/cell/in_table.rb +2 -4
- data/lib/prawn/table/cell/subtable.rb +2 -2
- data/lib/prawn/table/cell/text.rb +18 -41
- data/lib/prawn/table/cells.rb +48 -142
- data/lib/prawn/text.rb +25 -32
- data/lib/prawn/text/box.rb +6 -12
- data/lib/prawn/text/formatted.rb +4 -5
- data/lib/prawn/text/formatted/box.rb +59 -96
- data/lib/prawn/text/formatted/fragment.rb +23 -34
- data/lib/prawn/text/formatted/parser.rb +5 -15
- data/prawn.gemspec +13 -24
- data/spec/annotations_spec.rb +32 -16
- data/spec/bounding_box_spec.rb +17 -119
- data/spec/cell_spec.rb +42 -112
- data/spec/destinations_spec.rb +5 -5
- data/spec/document_spec.rb +111 -155
- data/spec/extensions/mocha.rb +0 -1
- data/spec/font_spec.rb +99 -149
- data/spec/formatted_text_arranger_spec.rb +43 -43
- data/spec/formatted_text_box_spec.rb +44 -43
- data/spec/formatted_text_fragment_spec.rb +8 -8
- data/spec/graphics_spec.rb +68 -151
- data/spec/grid_spec.rb +15 -26
- data/spec/images_spec.rb +30 -51
- data/spec/inline_formatted_text_parser_spec.rb +20 -69
- data/spec/jpg_spec.rb +4 -4
- data/spec/line_wrap_spec.rb +28 -28
- data/spec/measurement_units_spec.rb +6 -6
- data/spec/name_tree_spec.rb +112 -0
- data/spec/object_store_spec.rb +106 -17
- data/spec/outline_spec.rb +63 -103
- data/spec/pdf_object_spec.rb +170 -0
- data/spec/png_spec.rb +25 -25
- data/spec/reference_spec.rb +65 -8
- data/spec/repeater_spec.rb +10 -10
- data/spec/security_spec.rb +12 -44
- data/spec/snapshot_spec.rb +7 -7
- data/spec/span_spec.rb +15 -10
- data/spec/spec_helper.rb +8 -32
- data/spec/stamp_spec.rb +30 -29
- data/spec/stroke_styles_spec.rb +18 -36
- data/spec/table_spec.rb +111 -706
- data/spec/template_spec.rb +297 -0
- data/spec/text_at_spec.rb +33 -19
- data/spec/text_box_spec.rb +64 -100
- data/spec/text_rendering_mode_spec.rb +5 -5
- data/spec/text_spacing_spec.rb +4 -4
- data/spec/text_spec.rb +64 -84
- data/spec/transparency_spec.rb +5 -5
- metadata +290 -463
- checksums.yaml +0 -7
- data/.yardopts +0 -10
- data/Gemfile +0 -11
- data/data/images/16bit.color +0 -0
- data/data/images/dice.color +0 -0
- data/data/images/indexed_color.dat +0 -0
- data/data/images/indexed_color.png +0 -0
- data/data/images/page_white_text.color +0 -0
- data/lib/prawn/font_metric_cache.rb +0 -47
- data/lib/prawn/graphics/patterns.rb +0 -138
- data/lib/prawn/image_handler.rb +0 -36
- data/lib/prawn/soft_mask.rb +0 -96
- data/lib/prawn/table/cell/span_dummy.rb +0 -93
- data/lib/prawn/table/column_width_calculator.rb +0 -61
- data/lib/prawn/text/formatted/arranger.rb +0 -290
- data/lib/prawn/text/formatted/line_wrap.rb +0 -266
- data/lib/prawn/text/formatted/wrap.rb +0 -150
- data/lib/prawn/utilities.rb +0 -46
- data/manual/basic_concepts/adding_pages.rb +0 -27
- data/manual/basic_concepts/basic_concepts.rb +0 -34
- data/manual/basic_concepts/creation.rb +0 -39
- data/manual/basic_concepts/cursor.rb +0 -33
- data/manual/basic_concepts/measurement.rb +0 -25
- data/manual/basic_concepts/origin.rb +0 -38
- data/manual/basic_concepts/other_cursor_helpers.rb +0 -40
- data/manual/bounding_box/bounding_box.rb +0 -39
- data/manual/bounding_box/bounds.rb +0 -49
- data/manual/bounding_box/canvas.rb +0 -24
- data/manual/bounding_box/creation.rb +0 -23
- data/manual/bounding_box/indentation.rb +0 -46
- data/manual/bounding_box/nesting.rb +0 -45
- data/manual/bounding_box/russian_boxes.rb +0 -40
- data/manual/bounding_box/stretchy.rb +0 -31
- data/manual/document_and_page_options/background.rb +0 -27
- data/manual/document_and_page_options/document_and_page_options.rb +0 -32
- data/manual/document_and_page_options/metadata.rb +0 -23
- data/manual/document_and_page_options/page_margins.rb +0 -38
- data/manual/document_and_page_options/page_size.rb +0 -34
- data/manual/document_and_page_options/print_scaling.rb +0 -20
- data/manual/example_file.rb +0 -111
- data/manual/example_helper.rb +0 -411
- data/manual/example_package.rb +0 -53
- data/manual/example_section.rb +0 -46
- data/manual/graphics/circle_and_ellipse.rb +0 -22
- data/manual/graphics/color.rb +0 -24
- data/manual/graphics/common_lines.rb +0 -30
- data/manual/graphics/fill_and_stroke.rb +0 -42
- data/manual/graphics/fill_rules.rb +0 -37
- data/manual/graphics/gradients.rb +0 -37
- data/manual/graphics/graphics.rb +0 -58
- data/manual/graphics/helper.rb +0 -24
- data/manual/graphics/line_width.rb +0 -35
- data/manual/graphics/lines_and_curves.rb +0 -41
- data/manual/graphics/polygon.rb +0 -29
- data/manual/graphics/rectangle.rb +0 -21
- data/manual/graphics/rotate.rb +0 -28
- data/manual/graphics/scale.rb +0 -41
- data/manual/graphics/soft_masks.rb +0 -46
- data/manual/graphics/stroke_cap.rb +0 -31
- data/manual/graphics/stroke_dash.rb +0 -48
- data/manual/graphics/stroke_join.rb +0 -30
- data/manual/graphics/translate.rb +0 -29
- data/manual/graphics/transparency.rb +0 -35
- data/manual/images/absolute_position.rb +0 -23
- data/manual/images/fit.rb +0 -21
- data/manual/images/horizontal.rb +0 -25
- data/manual/images/images.rb +0 -40
- data/manual/images/plain_image.rb +0 -18
- data/manual/images/scale.rb +0 -22
- data/manual/images/vertical.rb +0 -28
- data/manual/images/width_and_height.rb +0 -25
- data/manual/layout/boxes.rb +0 -27
- data/manual/layout/content.rb +0 -25
- data/manual/layout/layout.rb +0 -28
- data/manual/layout/simple_grid.rb +0 -23
- data/manual/manual/cover.rb +0 -36
- data/manual/manual/foreword.rb +0 -85
- data/manual/manual/how_to_read_this_manual.rb +0 -41
- data/manual/manual/manual.rb +0 -34
- data/manual/outline/add_subsection_to.rb +0 -61
- data/manual/outline/insert_section_after.rb +0 -47
- data/manual/outline/outline.rb +0 -32
- data/manual/outline/sections_and_pages.rb +0 -67
- data/manual/repeatable_content/page_numbering.rb +0 -54
- data/manual/repeatable_content/repeatable_content.rb +0 -31
- data/manual/repeatable_content/repeater.rb +0 -55
- data/manual/repeatable_content/stamp.rb +0 -41
- data/manual/security/encryption.rb +0 -31
- data/manual/security/permissions.rb +0 -38
- data/manual/security/security.rb +0 -28
- 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/text/alignment.rb +0 -44
- data/manual/text/color.rb +0 -24
- data/manual/text/column_box.rb +0 -32
- data/manual/text/fallback_fonts.rb +0 -37
- data/manual/text/font.rb +0 -41
- data/manual/text/font_size.rb +0 -45
- data/manual/text/font_style.rb +0 -23
- data/manual/text/formatted_callbacks.rb +0 -60
- data/manual/text/formatted_text.rb +0 -54
- data/manual/text/free_flowing_text.rb +0 -51
- data/manual/text/group.rb +0 -31
- data/manual/text/inline.rb +0 -43
- data/manual/text/kerning_and_character_spacing.rb +0 -39
- data/manual/text/leading.rb +0 -25
- data/manual/text/line_wrapping.rb +0 -41
- data/manual/text/paragraph_indentation.rb +0 -26
- data/manual/text/positioned_text.rb +0 -38
- data/manual/text/registering_families.rb +0 -48
- data/manual/text/rendering_and_color.rb +0 -37
- data/manual/text/right_to_left_text.rb +0 -43
- data/manual/text/rotation.rb +0 -43
- data/manual/text/single_usage.rb +0 -37
- data/manual/text/text.rb +0 -75
- data/manual/text/text_box_excess.rb +0 -32
- data/manual/text/text_box_extensions.rb +0 -45
- data/manual/text/text_box_overflow.rb +0 -44
- data/manual/text/utf8.rb +0 -28
- data/manual/text/win_ansi_charset.rb +0 -59
- data/spec/acceptance/png.rb +0 -23
- data/spec/column_box_spec.rb +0 -65
- data/spec/extensions/encoding_helpers.rb +0 -9
- data/spec/font_metric_cache_spec.rb +0 -52
- data/spec/image_handler_spec.rb +0 -54
- data/spec/soft_mask_spec.rb +0 -117
- data/spec/table/span_dummy_spec.rb +0 -17
data/lib/prawn/images/image.rb
CHANGED
@@ -10,24 +10,23 @@ require 'digest/sha1'
|
|
10
10
|
module Prawn
|
11
11
|
module Images
|
12
12
|
class Image
|
13
|
-
# @group Extension API
|
14
13
|
|
15
14
|
def calc_image_dimensions(options)
|
16
15
|
w = options[:width] || width
|
17
16
|
h = options[:height] || height
|
18
17
|
|
19
18
|
if options[:width] && !options[:height]
|
20
|
-
wp = w / width.to_f
|
19
|
+
wp = w / width.to_f
|
21
20
|
w = width * wp
|
22
21
|
h = height * wp
|
23
|
-
elsif options[:height] && !options[:width]
|
22
|
+
elsif options[:height] && !options[:width]
|
24
23
|
hp = h / height.to_f
|
25
24
|
w = width * hp
|
26
|
-
h = height * hp
|
27
|
-
elsif options[:scale]
|
25
|
+
h = height * hp
|
26
|
+
elsif options[:scale]
|
28
27
|
w = width * options[:scale]
|
29
28
|
h = height * options[:scale]
|
30
|
-
elsif options[:fit]
|
29
|
+
elsif options[:fit]
|
31
30
|
bw, bh = options[:fit]
|
32
31
|
bp = bw / bh.to_f
|
33
32
|
ip = width / height.to_f
|
@@ -44,6 +43,23 @@ module Prawn
|
|
44
43
|
|
45
44
|
[w,h]
|
46
45
|
end
|
46
|
+
|
47
|
+
def self.detect_image_format(content)
|
48
|
+
top = content[0,128]
|
49
|
+
|
50
|
+
# Unpack before comparing for JPG header, so as to avoid having to worry
|
51
|
+
# about the source string encoding. We just want a byte-by-byte compare.
|
52
|
+
if top[0, 3].unpack("C*") == [255, 216, 255]
|
53
|
+
return :jpg
|
54
|
+
elsif top[0, 8].unpack("C*") == [137, 80, 78, 71, 13, 10, 26, 10]
|
55
|
+
return :png
|
56
|
+
else
|
57
|
+
raise Errors::UnsupportedImageType, "image file is an unrecognised format"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
|
47
62
|
end
|
48
63
|
end
|
49
64
|
end
|
65
|
+
|
data/lib/prawn/images/jpg.rb
CHANGED
@@ -10,21 +10,15 @@ require 'stringio'
|
|
10
10
|
|
11
11
|
module Prawn
|
12
12
|
module Images
|
13
|
-
|
14
13
|
# A convenience class that wraps the logic for extracting the parts
|
15
14
|
# of a JPG image that we need to embed them in a PDF
|
16
15
|
#
|
17
16
|
class JPG < Image
|
18
|
-
# @group Extension API
|
19
|
-
|
20
17
|
attr_reader :width, :height, :bits, :channels
|
21
18
|
attr_accessor :scaled_width, :scaled_height
|
22
|
-
|
23
|
-
JPEG_SOF_BLOCKS =
|
24
|
-
|
25
|
-
def self.can_render?(image_blob)
|
26
|
-
image_blob[0, 3].unpack("C*") == [255, 216, 255]
|
27
|
-
end
|
19
|
+
|
20
|
+
JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
|
21
|
+
JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
|
28
22
|
|
29
23
|
# Process a new JPG image
|
30
24
|
#
|
@@ -32,21 +26,20 @@ module Prawn
|
|
32
26
|
#
|
33
27
|
def initialize(data)
|
34
28
|
@data = data
|
35
|
-
|
36
|
-
d.binmode
|
29
|
+
data = StringIO.new(data.dup)
|
37
30
|
|
38
|
-
c_marker =
|
39
|
-
|
31
|
+
c_marker = "\xff" # Section marker.
|
32
|
+
data.read(2) # Skip the first two bytes of JPEG identifier.
|
40
33
|
loop do
|
41
|
-
marker, code, length =
|
34
|
+
marker, code, length = data.read(4).unpack('aan')
|
42
35
|
raise "JPEG marker not found!" if marker != c_marker
|
43
36
|
|
44
37
|
if JPEG_SOF_BLOCKS.include?(code)
|
45
|
-
@bits, @height, @width, @channels =
|
38
|
+
@bits, @height, @width, @channels = data.read(6).unpack("CnnC")
|
46
39
|
break
|
47
40
|
end
|
48
41
|
|
49
|
-
|
42
|
+
buffer = data.read(length - 2)
|
50
43
|
end
|
51
44
|
end
|
52
45
|
|
@@ -68,11 +61,13 @@ module Prawn
|
|
68
61
|
obj = document.ref!(
|
69
62
|
:Type => :XObject,
|
70
63
|
:Subtype => :Image,
|
64
|
+
:Filter => :DCTDecode,
|
71
65
|
:ColorSpace => color_space,
|
72
66
|
:BitsPerComponent => bits,
|
73
67
|
:Width => width,
|
74
|
-
:Height => height
|
75
|
-
|
68
|
+
:Height => height,
|
69
|
+
:Length => @data.size
|
70
|
+
)
|
76
71
|
|
77
72
|
# add extra decode params for CMYK images. By swapping the
|
78
73
|
# min and max values from the default, we invert the colours. See
|
@@ -81,8 +76,7 @@ module Prawn
|
|
81
76
|
obj.data[:Decode] = [ 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0 ]
|
82
77
|
end
|
83
78
|
|
84
|
-
obj
|
85
|
-
obj.stream.filters << :DCTDecode
|
79
|
+
obj << @data
|
86
80
|
obj
|
87
81
|
end
|
88
82
|
|
data/lib/prawn/images/png.rb
CHANGED
@@ -17,18 +17,12 @@ module Prawn
|
|
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
|
-
|
22
20
|
attr_reader :palette, :img_data, :transparency
|
23
21
|
attr_reader :width, :height, :bits
|
24
22
|
attr_reader :color_type, :compression_method, :filter_method
|
25
23
|
attr_reader :interlace_method, :alpha_channel
|
26
24
|
attr_accessor :scaled_width, :scaled_height
|
27
25
|
|
28
|
-
def self.can_render?(image_blob)
|
29
|
-
image_blob[0, 8].unpack("C*") == [137, 80, 78, 71, 13, 10, 26, 10]
|
30
|
-
end
|
31
|
-
|
32
26
|
# Process a new PNG image
|
33
27
|
#
|
34
28
|
# <tt>data</tt>:: A binary string of PNG data
|
@@ -94,8 +88,6 @@ module Prawn
|
|
94
88
|
|
95
89
|
data.read(4) # Skip the CRC
|
96
90
|
end
|
97
|
-
|
98
|
-
@img_data = Zlib::Inflate.inflate(@img_data)
|
99
91
|
end
|
100
92
|
|
101
93
|
# number of color components to each pixel
|
@@ -109,17 +101,34 @@ module Prawn
|
|
109
101
|
end
|
110
102
|
end
|
111
103
|
|
104
|
+
# number of bits used per pixel
|
105
|
+
#
|
106
|
+
def pixel_bitlength
|
107
|
+
if alpha_channel?
|
108
|
+
self.bits * (self.colors + 1)
|
109
|
+
else
|
110
|
+
self.bits * self.colors
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
112
114
|
# split the alpha channel data from the raw image data in images
|
113
115
|
# where it's required.
|
114
116
|
#
|
115
117
|
def split_alpha_channel!
|
116
|
-
|
118
|
+
unfilter_image_data if alpha_channel?
|
117
119
|
end
|
118
120
|
|
119
121
|
def alpha_channel?
|
120
122
|
@color_type == 4 || @color_type == 6
|
121
123
|
end
|
122
124
|
|
125
|
+
# Adobe Reader can't handle 16-bit png channels -- chop off the second
|
126
|
+
# byte (least significant)
|
127
|
+
#
|
128
|
+
def alpha_channel_bits
|
129
|
+
8
|
130
|
+
end
|
131
|
+
|
123
132
|
# Build a PDF object representing this image in +document+, and return
|
124
133
|
# a Reference to it.
|
125
134
|
#
|
@@ -159,31 +168,31 @@ module Prawn
|
|
159
168
|
:Subtype => :Image,
|
160
169
|
:Height => height,
|
161
170
|
:Width => width,
|
162
|
-
:BitsPerComponent => bits
|
171
|
+
:BitsPerComponent => bits,
|
172
|
+
:Length => img_data.size,
|
173
|
+
:Filter => :FlateDecode
|
163
174
|
)
|
164
175
|
|
176
|
+
unless alpha_channel
|
177
|
+
obj.data[:DecodeParms] = {:Predictor => 15,
|
178
|
+
:Colors => colors,
|
179
|
+
:BitsPerComponent => bits,
|
180
|
+
:Columns => width}
|
181
|
+
end
|
182
|
+
|
165
183
|
# append the actual image data to the object as a stream
|
166
184
|
obj << img_data
|
167
|
-
|
168
|
-
obj.stream.filters << {
|
169
|
-
:FlateDecode => {
|
170
|
-
:Predictor => 15,
|
171
|
-
:Colors => colors,
|
172
|
-
:BitsPerComponent => bits,
|
173
|
-
:Columns => width
|
174
|
-
}
|
175
|
-
}
|
176
|
-
|
185
|
+
|
177
186
|
# sort out the colours of the image
|
178
187
|
if palette.empty?
|
179
188
|
obj.data[:ColorSpace] = color
|
180
189
|
else
|
181
190
|
# embed the colour palette in the PDF as a object stream
|
182
|
-
palette_obj = document.ref!(
|
191
|
+
palette_obj = document.ref!(:Length => palette.size)
|
183
192
|
palette_obj << palette
|
184
193
|
|
185
194
|
# build the color space array for the image
|
186
|
-
obj.data[:ColorSpace] = [:Indexed,
|
195
|
+
obj.data[:ColorSpace] = [:Indexed,
|
187
196
|
:DeviceRGB,
|
188
197
|
(palette.size / 3) -1,
|
189
198
|
palette_obj]
|
@@ -224,20 +233,13 @@ module Prawn
|
|
224
233
|
:Subtype => :Image,
|
225
234
|
:Height => height,
|
226
235
|
:Width => width,
|
227
|
-
:BitsPerComponent =>
|
236
|
+
:BitsPerComponent => alpha_channel_bits,
|
237
|
+
:Length => alpha_channel.size,
|
238
|
+
:Filter => :FlateDecode,
|
228
239
|
:ColorSpace => :DeviceGray,
|
229
240
|
:Decode => [0, 1]
|
230
241
|
)
|
231
|
-
smask_obj
|
232
|
-
|
233
|
-
smask_obj.stream.filters << {
|
234
|
-
:FlateDecode => {
|
235
|
-
:Predictor => 15,
|
236
|
-
:Colors => 1,
|
237
|
-
:BitsPerComponent => bits,
|
238
|
-
:Columns => width
|
239
|
-
}
|
240
|
-
}
|
242
|
+
smask_obj << alpha_channel
|
241
243
|
obj.data[:SMask] = smask_obj
|
242
244
|
end
|
243
245
|
|
@@ -259,40 +261,95 @@ module Prawn
|
|
259
261
|
|
260
262
|
private
|
261
263
|
|
262
|
-
def
|
263
|
-
|
264
|
-
|
265
|
-
|
266
|
-
|
267
|
-
|
268
|
-
|
269
|
-
|
270
|
-
|
271
|
-
|
272
|
-
|
273
|
-
|
274
|
-
|
275
|
-
|
276
|
-
|
277
|
-
|
278
|
-
|
279
|
-
|
280
|
-
|
281
|
-
|
282
|
-
|
264
|
+
def unfilter_image_data
|
265
|
+
data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
|
266
|
+
@img_data = ""
|
267
|
+
@alpha_channel = ""
|
268
|
+
|
269
|
+
pixel_bytes = pixel_bitlength / 8
|
270
|
+
scanline_length = pixel_bytes * self.width + 1
|
271
|
+
row = 0
|
272
|
+
pixels = []
|
273
|
+
paeth, pa, pb, pc = nil
|
274
|
+
until data.empty? do
|
275
|
+
row_data = data.slice! 0, scanline_length
|
276
|
+
filter = row_data.shift
|
277
|
+
case filter
|
278
|
+
when 0 # None
|
279
|
+
when 1 # Sub
|
280
|
+
row_data.each_with_index do |byte, index|
|
281
|
+
left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
|
282
|
+
row_data[index] = (byte + left) % 256
|
283
|
+
#p [byte, left, row_data[index]]
|
284
|
+
end
|
285
|
+
when 2 # Up
|
286
|
+
row_data.each_with_index do |byte, index|
|
287
|
+
col = index / pixel_bytes
|
288
|
+
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
|
289
|
+
row_data[index] = (upper + byte) % 256
|
290
|
+
end
|
291
|
+
when 3 # Average
|
292
|
+
row_data.each_with_index do |byte, index|
|
293
|
+
col = index / pixel_bytes
|
294
|
+
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_bytes]
|
295
|
+
left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
|
283
296
|
|
284
|
-
|
297
|
+
row_data[index] = (byte + ((left + upper)/2).floor) % 256
|
298
|
+
end
|
299
|
+
when 4 # Paeth
|
300
|
+
left = upper = upper_left = nil
|
301
|
+
row_data.each_with_index do |byte, index|
|
302
|
+
col = index / pixel_bytes
|
303
|
+
|
304
|
+
left = index < pixel_bytes ? 0 : row_data[index - pixel_bytes]
|
305
|
+
if row.zero?
|
306
|
+
upper = upper_left = 0
|
307
|
+
else
|
308
|
+
upper = pixels[row-1][col][index % pixel_bytes]
|
309
|
+
upper_left = col.zero? ? 0 :
|
310
|
+
pixels[row-1][col-1][index % pixel_bytes]
|
311
|
+
end
|
312
|
+
|
313
|
+
p = left + upper - upper_left
|
314
|
+
pa = (p - left).abs
|
315
|
+
pb = (p - upper).abs
|
316
|
+
pc = (p - upper_left).abs
|
317
|
+
|
318
|
+
paeth = if pa <= pb && pa <= pc
|
319
|
+
left
|
320
|
+
elsif pb <= pc
|
321
|
+
upper
|
322
|
+
else
|
323
|
+
upper_left
|
324
|
+
end
|
325
|
+
|
326
|
+
row_data[index] = (byte + paeth) % 256
|
327
|
+
end
|
328
|
+
else
|
329
|
+
raise ArgumentError, "Invalid filter algorithm #{filter}"
|
330
|
+
end
|
285
331
|
|
286
|
-
|
287
|
-
|
332
|
+
s = []
|
333
|
+
row_data.each_slice pixel_bytes do |slice|
|
334
|
+
s << slice
|
335
|
+
end
|
336
|
+
pixels << s
|
337
|
+
row += 1
|
338
|
+
end
|
288
339
|
|
289
|
-
|
290
|
-
|
291
|
-
|
340
|
+
# convert the pixel data to seperate strings for colours and alpha
|
341
|
+
color_byte_size = self.colors * self.bits / 8
|
342
|
+
alpha_byte_size = alpha_channel_bits / 8
|
343
|
+
pixels.each do |this_row|
|
344
|
+
this_row.each do |pixel|
|
345
|
+
@img_data << pixel[0, color_byte_size].pack("C*")
|
346
|
+
@alpha_channel << pixel[color_byte_size, alpha_byte_size].pack("C*")
|
292
347
|
end
|
293
348
|
end
|
294
349
|
|
295
|
-
|
350
|
+
# compress the data
|
351
|
+
@img_data = Zlib::Deflate.deflate(@img_data)
|
352
|
+
@alpha_channel = Zlib::Deflate.deflate(@alpha_channel)
|
296
353
|
end
|
297
354
|
end
|
298
355
|
end
|
data/lib/prawn/layout.rb
CHANGED
@@ -1,15 +1,20 @@
|
|
1
|
-
|
2
|
-
|
1
|
+
require "prawn/table"
|
2
|
+
require 'prawn/layout/grid'
|
3
3
|
|
4
4
|
module Prawn
|
5
|
-
|
5
|
+
|
6
|
+
module Errors
|
7
|
+
|
8
|
+
# This error is raised when table data is malformed
|
9
|
+
#
|
10
|
+
InvalidTableData = Class.new(StandardError)
|
6
11
|
|
7
|
-
|
8
|
-
|
9
|
-
|
12
|
+
# This error is raised when an empty or nil table is rendered
|
13
|
+
#
|
14
|
+
EmptyTable = Class.new(StandardError)
|
15
|
+
end
|
10
16
|
|
11
|
-
|
12
|
-
|
13
|
-
|
14
|
-
end
|
17
|
+
module Layout
|
18
|
+
|
19
|
+
end
|
15
20
|
end
|
data/lib/prawn/layout/grid.rb
CHANGED
@@ -1,22 +1,15 @@
|
|
1
1
|
module Prawn
|
2
2
|
class Document
|
3
|
-
|
4
|
-
|
5
|
-
#
|
6
|
-
# rows and columns and the width to use for the gutter as the
|
3
|
+
|
4
|
+
# Defines the grid system for a particular document. Takes the number of
|
5
|
+
# rows and columns and the width to use for the gutter as the
|
7
6
|
# keys :rows, :columns, :gutter, :row_gutter, :column_gutter
|
8
7
|
#
|
9
|
-
# Note that a completely new grid object is built each time define_grid()
|
10
|
-
# is called. This means that all subsequent calls to grid() will use
|
11
|
-
# the newly defined Grid object -- grids are not nestable like
|
12
|
-
# bounding boxes are.
|
13
|
-
|
14
8
|
def define_grid(options = {})
|
15
|
-
@boxes = nil
|
16
9
|
@grid = Grid.new(self, options)
|
17
10
|
end
|
18
|
-
|
19
|
-
# A method that can either be used to access a particular grid on the page
|
11
|
+
|
12
|
+
# A method that can either be used to access a particular grid on the page
|
20
13
|
# or work with the grid system directly.
|
21
14
|
#
|
22
15
|
# @pdf.grid # Get the Grid directly
|
@@ -29,7 +22,7 @@ module Prawn
|
|
29
22
|
@grid
|
30
23
|
else
|
31
24
|
g1, g2 = args
|
32
|
-
if(g1.class == Array && g2.class == Array &&
|
25
|
+
if(g1.class == Array && g2.class == Array &&
|
33
26
|
g1.length == 2 && g2.length == 2)
|
34
27
|
multi_box(single_box(*g1), single_box(*g2))
|
35
28
|
else
|
@@ -37,17 +30,15 @@ module Prawn
|
|
37
30
|
end
|
38
31
|
end
|
39
32
|
end
|
40
|
-
|
41
|
-
# A Grid represents the entire grid system of a Page and calculates
|
33
|
+
|
34
|
+
# A Grid represents the entire grid system of a Page and calculates
|
42
35
|
# the column width and row height of the base box.
|
43
|
-
#
|
44
|
-
# @private
|
45
36
|
class Grid
|
46
37
|
attr_reader :pdf, :columns, :rows, :gutter, :row_gutter, :column_gutter
|
47
38
|
def initialize(pdf, options = {}) # :nodoc:
|
48
39
|
valid_options = [:columns, :rows, :gutter, :row_gutter, :column_gutter]
|
49
40
|
Prawn.verify_options valid_options, options
|
50
|
-
|
41
|
+
|
51
42
|
@pdf = pdf
|
52
43
|
@columns = options[:columns]
|
53
44
|
@rows = options[:rows]
|
@@ -58,7 +49,7 @@ module Prawn
|
|
58
49
|
def column_width
|
59
50
|
@column_width ||= subdivide(pdf.bounds.width, columns, column_gutter)
|
60
51
|
end
|
61
|
-
|
52
|
+
|
62
53
|
# Calculates the base height of boxes.
|
63
54
|
def row_height
|
64
55
|
@row_height ||= subdivide(pdf.bounds.height, rows, row_gutter)
|
@@ -74,11 +65,11 @@ module Prawn
|
|
74
65
|
end
|
75
66
|
|
76
67
|
private
|
77
|
-
|
68
|
+
|
78
69
|
def subdivide(total, num, gutter)
|
79
70
|
(total.to_f - (gutter * (num - 1).to_f)) / num.to_f
|
80
71
|
end
|
81
|
-
|
72
|
+
|
82
73
|
def set_gutter(options)
|
83
74
|
if options.has_key?(:gutter)
|
84
75
|
@gutter = options[:gutter].to_f
|
@@ -90,93 +81,92 @@ module Prawn
|
|
90
81
|
end
|
91
82
|
end
|
92
83
|
end
|
93
|
-
|
94
|
-
# A Box is a class that represents a bounded area of a page.
|
95
|
-
# A Grid object has methods that allow easy access to the coordinates of
|
84
|
+
|
85
|
+
# A Box is a class that represents a bounded area of a page.
|
86
|
+
# A Grid object has methods that allow easy access to the coordinates of
|
96
87
|
# its corners, which can be plugged into most existing prawnmethods.
|
97
88
|
#
|
98
|
-
|
99
|
-
class GridBox
|
89
|
+
class Box #:nodoc:
|
100
90
|
attr_reader :pdf
|
101
|
-
|
91
|
+
|
102
92
|
def initialize(pdf, i, j)
|
103
93
|
@pdf = pdf
|
104
94
|
@i = i
|
105
95
|
@j = j
|
106
96
|
end
|
107
|
-
|
108
|
-
# Mostly diagnostic method that outputs the name of a box as
|
97
|
+
|
98
|
+
# Mostly diagnostic method that outputs the name of a box as
|
109
99
|
# col_num, row_num
|
110
100
|
#
|
111
101
|
def name
|
112
102
|
"#{@i.to_s},#{@j.to_s}"
|
113
103
|
end
|
114
|
-
|
104
|
+
|
115
105
|
# :nodoc
|
116
106
|
def total_height
|
117
107
|
pdf.bounds.height.to_f
|
118
108
|
end
|
119
|
-
|
109
|
+
|
120
110
|
# Width of a box
|
121
111
|
def width
|
122
112
|
grid.column_width.to_f
|
123
113
|
end
|
124
|
-
|
114
|
+
|
125
115
|
# Height of a box
|
126
116
|
def height
|
127
117
|
grid.row_height.to_f
|
128
118
|
end
|
129
|
-
|
119
|
+
|
130
120
|
# Width of the gutter
|
131
121
|
def gutter
|
132
122
|
grid.gutter.to_f
|
133
123
|
end
|
134
|
-
|
124
|
+
|
135
125
|
# x-coordinate of left side
|
136
126
|
def left
|
137
127
|
@left ||= (width + grid.column_gutter) * @j.to_f
|
138
128
|
end
|
139
|
-
|
140
|
-
# x-coordinate of right side
|
129
|
+
|
130
|
+
# x-coordinate of right side
|
141
131
|
def right
|
142
132
|
@right ||= left + width
|
143
133
|
end
|
144
|
-
|
134
|
+
|
145
135
|
# y-coordinate of the top
|
146
136
|
def top
|
147
137
|
@top ||= total_height - ((height + grid.row_gutter) * @i.to_f)
|
148
138
|
end
|
149
|
-
|
139
|
+
|
150
140
|
# y-coordinate of the bottom
|
151
141
|
def bottom
|
152
142
|
@bottom ||= top - height
|
153
143
|
end
|
154
|
-
|
144
|
+
|
155
145
|
# x,y coordinates of top left corner
|
156
146
|
def top_left
|
157
147
|
[left, top]
|
158
148
|
end
|
159
|
-
|
160
|
-
# x,y coordinates of top right corner
|
149
|
+
|
150
|
+
# x,y coordinates of top right corner
|
161
151
|
def top_right
|
162
152
|
[right, top]
|
163
153
|
end
|
164
|
-
|
154
|
+
|
165
155
|
# x,y coordinates of bottom left corner
|
166
156
|
def bottom_left
|
167
157
|
[left, bottom]
|
168
158
|
end
|
169
|
-
|
159
|
+
|
170
160
|
# x,y coordinates of bottom right corner
|
171
161
|
def bottom_right
|
172
162
|
[right, bottom]
|
173
163
|
end
|
174
|
-
|
164
|
+
|
175
165
|
# Creates a standard bounding box based on the grid box.
|
176
166
|
def bounding_box(&blk)
|
177
167
|
pdf.bounding_box(top_left, :width => width, :height => height, &blk)
|
178
168
|
end
|
179
|
-
|
169
|
+
|
180
170
|
# Diagnostic method
|
181
171
|
def show(grid_color = "CCCCCC")
|
182
172
|
self.bounding_box do
|
@@ -185,30 +175,28 @@ module Prawn
|
|
185
175
|
pdf.stroke_color = grid_color
|
186
176
|
pdf.text self.name
|
187
177
|
pdf.stroke_bounds
|
188
|
-
|
178
|
+
|
189
179
|
pdf.stroke_color = original_stroke_color
|
190
180
|
end
|
191
181
|
end
|
192
|
-
|
182
|
+
|
193
183
|
private
|
194
184
|
def grid
|
195
185
|
pdf.grid
|
196
186
|
end
|
197
187
|
end
|
198
|
-
|
188
|
+
|
199
189
|
# A MultiBox is specified by 2 Boxes and spans the areas between.
|
200
|
-
|
201
|
-
# @private
|
202
|
-
class MultiBox < GridBox #:nodoc:
|
190
|
+
class MultiBox < Box #:nodoc:
|
203
191
|
def initialize(pdf, b1, b2)
|
204
192
|
@pdf = pdf
|
205
193
|
@bs = [b1, b2]
|
206
194
|
end
|
207
|
-
|
195
|
+
|
208
196
|
def name
|
209
197
|
@bs.map {|b| b.name}.join(":")
|
210
198
|
end
|
211
|
-
|
199
|
+
|
212
200
|
def total_height
|
213
201
|
@bs[0].total_height
|
214
202
|
end
|
@@ -216,54 +204,54 @@ module Prawn
|
|
216
204
|
def width
|
217
205
|
right_box.right - left_box.left
|
218
206
|
end
|
219
|
-
|
207
|
+
|
220
208
|
def height
|
221
209
|
top_box.top - bottom_box.bottom
|
222
210
|
end
|
223
|
-
|
211
|
+
|
224
212
|
def gutter
|
225
213
|
@bs[0].gutter
|
226
214
|
end
|
227
|
-
|
215
|
+
|
228
216
|
def left
|
229
217
|
left_box.left
|
230
218
|
end
|
231
|
-
|
219
|
+
|
232
220
|
def right
|
233
221
|
right_box.right
|
234
222
|
end
|
235
|
-
|
223
|
+
|
236
224
|
def top
|
237
225
|
top_box.top
|
238
226
|
end
|
239
|
-
|
227
|
+
|
240
228
|
def bottom
|
241
229
|
bottom_box.bottom
|
242
230
|
end
|
243
|
-
|
231
|
+
|
244
232
|
private
|
245
233
|
def left_box
|
246
234
|
@left_box ||= @bs.min {|a,b| a.left <=> b.left}
|
247
235
|
end
|
248
|
-
|
236
|
+
|
249
237
|
def right_box
|
250
238
|
@right_box ||= @bs.max {|a,b| a.right <=> b.right}
|
251
239
|
end
|
252
|
-
|
240
|
+
|
253
241
|
def top_box
|
254
242
|
@top_box ||= @bs.max {|a,b| a.top <=> b.top}
|
255
243
|
end
|
256
|
-
|
244
|
+
|
257
245
|
def bottom_box
|
258
246
|
@bottom_box ||= @bs.min {|a,b| a.bottom <=> b.bottom}
|
259
247
|
end
|
260
248
|
end
|
261
|
-
|
249
|
+
|
262
250
|
private
|
263
251
|
def single_box(i, j)
|
264
|
-
|
252
|
+
Box.new(self, i, j)
|
265
253
|
end
|
266
|
-
|
254
|
+
|
267
255
|
def multi_box(b1, b2)
|
268
256
|
MultiBox.new(self, b1, b2)
|
269
257
|
end
|