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.
- data/COPYING +340 -0
- data/LICENSE +56 -0
- data/README +47 -0
- data/Rakefile +76 -0
- data/data/fonts/Activa.ttf +0 -0
- data/data/fonts/Chalkboard.ttf +0 -0
- data/data/fonts/Courier-Bold.afm +342 -0
- data/data/fonts/Courier-BoldOblique.afm +342 -0
- data/data/fonts/Courier-Oblique.afm +342 -0
- data/data/fonts/Courier.afm +342 -0
- data/data/fonts/DejaVuSans.ttf +0 -0
- data/data/fonts/Dustismo_Roman.ttf +0 -0
- data/data/fonts/Helvetica-Bold.afm +2827 -0
- data/data/fonts/Helvetica-BoldOblique.afm +2827 -0
- data/data/fonts/Helvetica-Oblique.afm +3051 -0
- data/data/fonts/Helvetica.afm +3051 -0
- data/data/fonts/MustRead.html +19 -0
- data/data/fonts/Symbol.afm +213 -0
- data/data/fonts/Times-Bold.afm +2588 -0
- data/data/fonts/Times-BoldItalic.afm +2384 -0
- data/data/fonts/Times-Italic.afm +2667 -0
- data/data/fonts/Times-Roman.afm +2419 -0
- data/data/fonts/ZapfDingbats.afm +225 -0
- data/data/fonts/comicsans.ttf +0 -0
- data/data/fonts/gkai00mp.ttf +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/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/rails.dat +0 -0
- data/data/images/rails.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/web-links.dat +1 -0
- data/data/images/web-links.png +0 -0
- data/data/shift_jis_text.txt +1 -0
- data/examples/addressbook.csv +6 -0
- data/examples/alignment.rb +16 -0
- data/examples/bounding_boxes.rb +30 -0
- data/examples/canvas.rb +12 -0
- data/examples/cell.rb +38 -0
- data/examples/chinese_text_wrapping.rb +17 -0
- data/examples/currency.csv +1834 -0
- data/examples/curves.rb +10 -0
- data/examples/family_based_styling.rb +21 -0
- data/examples/fancy_table.rb +61 -0
- data/examples/flowing_text_with_header_and_footer.rb +72 -0
- data/examples/font_size.rb +27 -0
- data/examples/hexagon.rb +14 -0
- data/examples/image.rb +23 -0
- data/examples/image2.rb +13 -0
- data/examples/image_flow.rb +34 -0
- data/examples/kerning.rb +27 -0
- data/examples/lazy_bounding_boxes.rb +19 -0
- data/examples/line.rb +31 -0
- data/examples/multi_page_layout.rb +14 -0
- data/examples/page_geometry.rb +28 -0
- data/examples/png_types.rb +23 -0
- data/examples/polygons.rb +16 -0
- data/examples/position_by_baseline.rb +26 -0
- data/examples/ruport_formatter.rb +50 -0
- data/examples/ruport_helpers.rb +18 -0
- data/examples/russian_boxes.rb +34 -0
- data/examples/simple_text.rb +15 -0
- data/examples/simple_text_ttf.rb +16 -0
- data/examples/sjis.rb +21 -0
- data/examples/span.rb +27 -0
- data/examples/table.rb +47 -0
- data/examples/table_header_color.rb +16 -0
- data/examples/text_flow.rb +65 -0
- data/examples/top_and_bottom_cells.rb +40 -0
- data/examples/utf8.rb +12 -0
- data/lib/prawn.rb +67 -0
- data/lib/prawn/compatibility.rb +46 -0
- data/lib/prawn/document.rb +309 -0
- data/lib/prawn/document/bounding_box.rb +362 -0
- data/lib/prawn/document/internals.rb +113 -0
- data/lib/prawn/document/page_geometry.rb +79 -0
- data/lib/prawn/document/span.rb +47 -0
- data/lib/prawn/document/table.rb +350 -0
- data/lib/prawn/document/text.rb +196 -0
- data/lib/prawn/errors.rb +48 -0
- data/lib/prawn/font.rb +356 -0
- data/lib/prawn/font/cmap.rb +59 -0
- data/lib/prawn/font/metrics.rb +378 -0
- data/lib/prawn/font/wrapping.rb +47 -0
- data/lib/prawn/graphics.rb +252 -0
- data/lib/prawn/graphics/cell.rb +264 -0
- data/lib/prawn/graphics/color.rb +132 -0
- data/lib/prawn/images.rb +336 -0
- data/lib/prawn/images/jpg.rb +45 -0
- data/lib/prawn/images/png.rb +199 -0
- data/lib/prawn/pdf_object.rb +73 -0
- data/lib/prawn/reference.rb +56 -0
- data/spec/bounding_box_spec.rb +141 -0
- data/spec/document_spec.rb +181 -0
- data/spec/font_spec.rb +141 -0
- data/spec/graphics_spec.rb +209 -0
- data/spec/images_spec.rb +68 -0
- data/spec/jpg_spec.rb +25 -0
- data/spec/metrics_spec.rb +62 -0
- data/spec/pdf_object_spec.rb +112 -0
- data/spec/png_spec.rb +196 -0
- data/spec/reference_spec.rb +42 -0
- data/spec/spec_helper.rb +23 -0
- data/spec/table_spec.rb +179 -0
- data/spec/text_spec.rb +135 -0
- metadata +181 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
# encoding: ASCII-8BIT
|
|
2
|
+
|
|
3
|
+
# jpg.rb : Extracts the data from a JPG that is needed for embedding
|
|
4
|
+
#
|
|
5
|
+
# Copyright April 2008, James Healy. All Rights Reserved.
|
|
6
|
+
#
|
|
7
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
8
|
+
|
|
9
|
+
require 'stringio'
|
|
10
|
+
|
|
11
|
+
module Prawn
|
|
12
|
+
module Images
|
|
13
|
+
# A convenience class that wraps the logic for extracting the parts
|
|
14
|
+
# of a PNG image that we need to embed them in a PDF
|
|
15
|
+
class JPG
|
|
16
|
+
attr_reader :width, :height, :bits, :channels
|
|
17
|
+
attr_accessor :scaled_width, :scaled_height
|
|
18
|
+
|
|
19
|
+
JPEG_SOF_BLOCKS = %W(\xc0 \xc1 \xc2 \xc3 \xc5 \xc6 \xc7 \xc9 \xca \xcb \xcd \xce \xcf)
|
|
20
|
+
JPEG_APP_BLOCKS = %W(\xe0 \xe1 \xe2 \xe3 \xe4 \xe5 \xe6 \xe7 \xe8 \xe9 \xea \xeb \xec \xed \xee \xef)
|
|
21
|
+
|
|
22
|
+
# Process a new JPG image
|
|
23
|
+
#
|
|
24
|
+
# <tt>:data</tt>:: A string containing a full PNG file
|
|
25
|
+
#
|
|
26
|
+
def initialize(data)
|
|
27
|
+
data = StringIO.new(data.dup)
|
|
28
|
+
|
|
29
|
+
c_marker = "\xff" # Section marker.
|
|
30
|
+
data.read(2) # Skip the first two bytes of JPEG identifier.
|
|
31
|
+
loop do
|
|
32
|
+
marker, code, length = data.read(4).unpack('aan')
|
|
33
|
+
raise "JPEG marker not found!" if marker != c_marker
|
|
34
|
+
|
|
35
|
+
if JPEG_SOF_BLOCKS.include?(code)
|
|
36
|
+
@bits, @height, @width, @channels = data.read(6).unpack("CnnC")
|
|
37
|
+
break
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
buffer = data.read(length - 2)
|
|
41
|
+
end
|
|
42
|
+
end
|
|
43
|
+
end
|
|
44
|
+
end
|
|
45
|
+
end
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
# encoding: ASCII-8BIT
|
|
2
|
+
|
|
3
|
+
# png.rb : Extracts the data from a PNG that is needed for embedding
|
|
4
|
+
#
|
|
5
|
+
# Based on some similar code in PDF::Writer by Austin Ziegler
|
|
6
|
+
#
|
|
7
|
+
# Copyright April 2008, James Healy. All Rights Reserved.
|
|
8
|
+
#
|
|
9
|
+
# This is free software. Please see the LICENSE and COPYING files for details.
|
|
10
|
+
|
|
11
|
+
require 'stringio'
|
|
12
|
+
|
|
13
|
+
module Prawn
|
|
14
|
+
module Images
|
|
15
|
+
# A convenience class that wraps the logic for extracting the parts
|
|
16
|
+
# of a PNG image that we need to embed them in a PDF
|
|
17
|
+
class PNG
|
|
18
|
+
attr_reader :palette, :img_data, :transparency
|
|
19
|
+
attr_reader :width, :height, :bits
|
|
20
|
+
attr_reader :color_type, :compression_method, :filter_method
|
|
21
|
+
attr_reader :interlace_method, :alpha_channel
|
|
22
|
+
attr_accessor :scaled_width, :scaled_height
|
|
23
|
+
|
|
24
|
+
# Process a new PNG image
|
|
25
|
+
#
|
|
26
|
+
# <tt>:data</tt>:: A string containing a full PNG file
|
|
27
|
+
#
|
|
28
|
+
def initialize(data)
|
|
29
|
+
data = StringIO.new(data.dup)
|
|
30
|
+
|
|
31
|
+
data.read(8) # Skip the default header
|
|
32
|
+
|
|
33
|
+
@palette = ""
|
|
34
|
+
@img_data = ""
|
|
35
|
+
@transparency = {}
|
|
36
|
+
|
|
37
|
+
loop do
|
|
38
|
+
chunk_size = data.read(4).unpack("N")[0]
|
|
39
|
+
section = data.read(4)
|
|
40
|
+
case section
|
|
41
|
+
when 'IHDR'
|
|
42
|
+
# we can grab other interesting values from here (like width,
|
|
43
|
+
# height, etc)
|
|
44
|
+
values = data.read(chunk_size).unpack("NNCCCCC")
|
|
45
|
+
|
|
46
|
+
@width = values[0]
|
|
47
|
+
@height = values[1]
|
|
48
|
+
@bits = values[2]
|
|
49
|
+
@color_type = values[3]
|
|
50
|
+
@compression_method = values[4]
|
|
51
|
+
@filter_method = values[5]
|
|
52
|
+
@interlace_method = values[6]
|
|
53
|
+
when 'PLTE'
|
|
54
|
+
@palette << data.read(chunk_size)
|
|
55
|
+
when 'IDAT'
|
|
56
|
+
@img_data << data.read(chunk_size)
|
|
57
|
+
when 'tRNS'
|
|
58
|
+
# This chunk can only occur once and it must occur after the
|
|
59
|
+
# PLTE chunk and before the IDAT chunk
|
|
60
|
+
@transparency = {}
|
|
61
|
+
case @color_type
|
|
62
|
+
when 3
|
|
63
|
+
# Indexed colour, RGB. Each byte in this chunk is an alpha for
|
|
64
|
+
# the palette index in the PLTE ("palette") chunk up until the
|
|
65
|
+
# last non-opaque entry. Set up an array, stretching over all
|
|
66
|
+
# palette entries which will be 0 (opaque) or 1 (transparent).
|
|
67
|
+
@transparency[:indexed] = data.read(chunk_size).unpack("C*")
|
|
68
|
+
short = 255 - @transparency[:indexed].size
|
|
69
|
+
@transparency[:indexed] += ([255] * short) if short > 0
|
|
70
|
+
when 0
|
|
71
|
+
# Greyscale. Corresponding to entries in the PLTE chunk.
|
|
72
|
+
# Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
|
|
73
|
+
grayval = data.read(chunk_size).unpack("n").first
|
|
74
|
+
@transparency[:grayscale] = grayval
|
|
75
|
+
when 2
|
|
76
|
+
# True colour with proper alpha channel.
|
|
77
|
+
@transparency[:rgb] = data.read(chunk_size).unpack("nnn")
|
|
78
|
+
end
|
|
79
|
+
when 'IEND'
|
|
80
|
+
# we've got everything we need, exit the loop
|
|
81
|
+
break
|
|
82
|
+
else
|
|
83
|
+
# unknown (or un-important) section, skip over it
|
|
84
|
+
data.seek(data.pos + chunk_size)
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
data.read(4) # Skip the CRC
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# if our img_data contains alpha channel data, split it out
|
|
91
|
+
unfilter_image_data if alpha_channel?
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
def pixel_bytes
|
|
95
|
+
@pixel_bytes ||= case @color_type
|
|
96
|
+
when 0, 3, 4 then 1
|
|
97
|
+
when 1, 2, 6 then 3
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
private
|
|
102
|
+
|
|
103
|
+
def alpha_channel?
|
|
104
|
+
@color_type == 4 || @color_type == 6
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
def unfilter_image_data
|
|
108
|
+
data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
|
|
109
|
+
@img_data = ""
|
|
110
|
+
@alpha_channel = ""
|
|
111
|
+
|
|
112
|
+
# each pixel has the color bytes, plus a byte of alpha channel
|
|
113
|
+
pixel_length = pixel_bytes + 1
|
|
114
|
+
scanline_length = pixel_length * @width + 1 # for filter
|
|
115
|
+
row = 0
|
|
116
|
+
pixels = []
|
|
117
|
+
paeth, pa, pb, pc = nil
|
|
118
|
+
until data.empty? do
|
|
119
|
+
row_data = data.slice! 0, scanline_length
|
|
120
|
+
filter = row_data.shift
|
|
121
|
+
case filter
|
|
122
|
+
when 0 # None
|
|
123
|
+
when 1 # Sub
|
|
124
|
+
row_data.each_with_index do |byte, index|
|
|
125
|
+
left = index < pixel_length ? 0 : row_data[index - pixel_length]
|
|
126
|
+
row_data[index] = (byte + left) % 256
|
|
127
|
+
#p [byte, left, row_data[index]]
|
|
128
|
+
end
|
|
129
|
+
when 2 # Up
|
|
130
|
+
row_data.each_with_index do |byte, index|
|
|
131
|
+
col = index / pixel_length
|
|
132
|
+
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_length]
|
|
133
|
+
row_data[index] = (upper + byte) % 256
|
|
134
|
+
end
|
|
135
|
+
when 3 # Average
|
|
136
|
+
row_data.each_with_index do |byte, index|
|
|
137
|
+
col = index / pixel_length
|
|
138
|
+
upper = row == 0 ? 0 : pixels[row-1][col][index % pixel_length]
|
|
139
|
+
left = index < pixel_length ? 0 : row_data[index - pixel_length]
|
|
140
|
+
|
|
141
|
+
row_data[index] = (byte + ((left + upper)/2).floor) % 256
|
|
142
|
+
end
|
|
143
|
+
when 4 # Paeth
|
|
144
|
+
left = upper = upper_left = nil
|
|
145
|
+
row_data.each_with_index do |byte, index|
|
|
146
|
+
col = index / pixel_length
|
|
147
|
+
|
|
148
|
+
left = index < pixel_length ? 0 : row_data[index - pixel_length]
|
|
149
|
+
if row.zero?
|
|
150
|
+
upper = upper_left = 0
|
|
151
|
+
else
|
|
152
|
+
upper = pixels[row-1][col][index % pixel_length]
|
|
153
|
+
upper_left = col.zero? ? 0 :
|
|
154
|
+
pixels[row-1][col-1][index % pixel_length]
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
p = left + upper - upper_left
|
|
158
|
+
pa = (p - left).abs
|
|
159
|
+
pb = (p - upper).abs
|
|
160
|
+
pc = (p - upper_left).abs
|
|
161
|
+
|
|
162
|
+
paeth = if pa <= pb && pa <= pc
|
|
163
|
+
left
|
|
164
|
+
elsif pb <= pc
|
|
165
|
+
upper
|
|
166
|
+
else
|
|
167
|
+
upper_left
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
row_data[index] = (byte + paeth) % 256
|
|
171
|
+
#p [byte, paeth, row_data[index]]
|
|
172
|
+
end
|
|
173
|
+
else
|
|
174
|
+
raise ArgumentError, "Invalid filter algorithm #{filter}"
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
s = []
|
|
178
|
+
row_data.each_slice pixel_length do |slice|
|
|
179
|
+
s << slice
|
|
180
|
+
end
|
|
181
|
+
pixels << s
|
|
182
|
+
row += 1
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
# convert the pixel data to seperate strings for colours and alpha
|
|
186
|
+
pixels.each do |row|
|
|
187
|
+
row.each do |pixel|
|
|
188
|
+
@img_data << pixel[0,pixel_bytes].pack("C*")
|
|
189
|
+
@alpha_channel << pixel.last
|
|
190
|
+
end
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
# compress the data
|
|
194
|
+
@img_data = Zlib::Deflate.deflate(@img_data)
|
|
195
|
+
@alpha_channel = Zlib::Deflate.deflate(@alpha_channel)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
end
|
|
199
|
+
end
|
|
@@ -0,0 +1,73 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
#
|
|
3
|
+
# pdf_object.rb : Handles Ruby to PDF object serialization
|
|
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
|
+
# Top level Module
|
|
10
|
+
#
|
|
11
|
+
module Prawn
|
|
12
|
+
|
|
13
|
+
module_function
|
|
14
|
+
|
|
15
|
+
# Serializes Ruby objects to their PDF equivalents. Most primitive objects
|
|
16
|
+
# will work as expected, but please note that Name objects are represented
|
|
17
|
+
# by Ruby Symbol objects and Dictionary objects are represented by Ruby hashes
|
|
18
|
+
# (keyed by symbols)
|
|
19
|
+
#
|
|
20
|
+
# Examples:
|
|
21
|
+
#
|
|
22
|
+
# PdfObject(true) #=> "true"
|
|
23
|
+
# PdfObject(false) #=> "false"
|
|
24
|
+
# PdfObject(1.2124) #=> "1.2124"
|
|
25
|
+
# PdfObject("foo bar") #=> "(foo bar)"
|
|
26
|
+
# PdfObject(:Symbol) #=> "/Symbol"
|
|
27
|
+
# PdfObject(["foo",:bar, [1,2]]) #=> "[foo /bar [1 2]]"
|
|
28
|
+
#
|
|
29
|
+
def PdfObject(obj, in_content_stream = false)
|
|
30
|
+
case(obj)
|
|
31
|
+
when NilClass then "null"
|
|
32
|
+
when TrueClass then "true"
|
|
33
|
+
when FalseClass then "false"
|
|
34
|
+
when Numeric then String(obj)
|
|
35
|
+
when Array
|
|
36
|
+
"[" << obj.map { |e| PdfObject(e, in_content_stream) }.join(' ') << "]"
|
|
37
|
+
when Prawn::LiteralString
|
|
38
|
+
obj = obj.gsub(/[\\\n\(\)]/) { |m| "\\#{m}" }
|
|
39
|
+
"(#{obj})"
|
|
40
|
+
when String
|
|
41
|
+
obj = "\xFE\xFF" + obj.unpack("U*").pack("n*") unless in_content_stream
|
|
42
|
+
"<" << obj.unpack("H*").first << ">"
|
|
43
|
+
when Symbol
|
|
44
|
+
if (obj = obj.to_s) =~ /\s/
|
|
45
|
+
raise Prawn::Errors::FailedObjectConversion,
|
|
46
|
+
"A PDF Name cannot contain whitespace"
|
|
47
|
+
else
|
|
48
|
+
"/" << obj
|
|
49
|
+
end
|
|
50
|
+
when Hash
|
|
51
|
+
output = "<< "
|
|
52
|
+
obj.each do |k,v|
|
|
53
|
+
unless String === k || Symbol === k
|
|
54
|
+
raise Prawn::Errors::FailedObjectConversion,
|
|
55
|
+
"A PDF Dictionary must be keyed by names"
|
|
56
|
+
end
|
|
57
|
+
output << PdfObject(k.to_sym, in_content_stream) << " " <<
|
|
58
|
+
PdfObject(v, in_content_stream) << "\n"
|
|
59
|
+
end
|
|
60
|
+
output << ">>"
|
|
61
|
+
when Prawn::Reference
|
|
62
|
+
obj.to_s
|
|
63
|
+
when Prawn::NameTree::Node
|
|
64
|
+
PdfObject(obj.to_hash)
|
|
65
|
+
when Prawn::NameTree::Value
|
|
66
|
+
PdfObject(obj.name) + " " + PdfObject(obj.value)
|
|
67
|
+
else
|
|
68
|
+
raise Prawn::Errors::FailedObjectConversion,
|
|
69
|
+
"This object cannot be serialized to PDF"
|
|
70
|
+
end
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
end
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
# reference.rb : Implementation of PDF indirect objects
|
|
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
|
+
require 'zlib'
|
|
10
|
+
|
|
11
|
+
module Prawn
|
|
12
|
+
|
|
13
|
+
class Reference #:nodoc:
|
|
14
|
+
|
|
15
|
+
attr_accessor :gen, :data, :offset
|
|
16
|
+
attr_reader :identifier, :stream
|
|
17
|
+
|
|
18
|
+
def initialize(id,data)
|
|
19
|
+
@identifier = id
|
|
20
|
+
@gen = 0
|
|
21
|
+
@data = data
|
|
22
|
+
@compressed = false
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def object
|
|
26
|
+
output = "#{@identifier} #{gen} obj\n" <<
|
|
27
|
+
Prawn::PdfObject(data) << "\n"
|
|
28
|
+
if @stream
|
|
29
|
+
output << "stream\n" << @stream << "\nendstream\n"
|
|
30
|
+
end
|
|
31
|
+
output << "endobj\n"
|
|
32
|
+
end
|
|
33
|
+
|
|
34
|
+
def <<(data)
|
|
35
|
+
raise 'Cannot add data to a stream that is compressed' if @compressed
|
|
36
|
+
(@stream ||= "") << data
|
|
37
|
+
end
|
|
38
|
+
|
|
39
|
+
def to_s
|
|
40
|
+
"#{@identifier} #{gen} R"
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
def compress_stream
|
|
44
|
+
@stream = Zlib::Deflate.deflate(@stream)
|
|
45
|
+
@data[:Filter] = :FlateDecode
|
|
46
|
+
@compressed = true
|
|
47
|
+
end
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
module_function
|
|
51
|
+
|
|
52
|
+
def Reference(*args) #:nodoc:
|
|
53
|
+
Reference.new(*args)
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
|
4
|
+
|
|
5
|
+
describe "A bounding box" do
|
|
6
|
+
|
|
7
|
+
before(:each) do
|
|
8
|
+
@x = 100
|
|
9
|
+
@y = 125
|
|
10
|
+
@width = 50
|
|
11
|
+
@height = 75
|
|
12
|
+
@box = Prawn::Document::BoundingBox.new(nil, [@x,@y], :width => @width,
|
|
13
|
+
:height => @height )
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
it "should have an anchor at (x, y - height)" do
|
|
17
|
+
@box.anchor.should == [@x,@y-@height]
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
it "should have a left boundary of 0" do
|
|
21
|
+
@box.left.should == 0
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should have a right boundary equal to the width" do
|
|
25
|
+
@box.right.should == @width
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
it "should have a top boundary of height" do
|
|
29
|
+
@box.top.should == @height
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should have a bottom boundary of 0" do
|
|
33
|
+
@box.bottom.should == 0
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "should have a top-left of [0,height]" do
|
|
37
|
+
@box.top_left.should == [0,@height]
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
it "should have a top-right of [width,height]" do
|
|
41
|
+
@box.top_right.should == [@width,@height]
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
it "should have a bottom-left of [0,0]" do
|
|
45
|
+
@box.bottom_left.should == [0,0]
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
it "should have a bottom-right of [width,0]" do
|
|
49
|
+
@box.bottom_right.should == [@width,0]
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
it "should have an absolute left boundary of x" do
|
|
53
|
+
@box.absolute_left.should == @x
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "should have an absolute right boundary of x + width" do
|
|
57
|
+
@box.absolute_right.should == @x + @width
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should have an absolute top boundary of y" do
|
|
61
|
+
@box.absolute_top.should == @y
|
|
62
|
+
end
|
|
63
|
+
|
|
64
|
+
it "should have an absolute bottom boundary of y - height" do
|
|
65
|
+
@box.absolute_bottom.should == @y - @height
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
it "should have an absolute bottom-left of [x,y-height]" do
|
|
69
|
+
@box.absolute_bottom_left.should == [@x, @y - @height]
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
it "should have an absolute bottom-right of [x+width,y-height]" do
|
|
73
|
+
@box.absolute_bottom_right.should == [@x + @width , @y - @height]
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
it "should have an absolute top-left of [x,y]" do
|
|
77
|
+
@box.absolute_top_left.should == [@x, @y]
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
it "should have an absolute top-right of [x+width,y]" do
|
|
81
|
+
@box.absolute_top_right.should == [@x + @width, @y]
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "drawing bounding boxes" do
|
|
88
|
+
|
|
89
|
+
before(:each) { create_pdf }
|
|
90
|
+
|
|
91
|
+
it "should restore the margin box when bounding box exits" do
|
|
92
|
+
margin_box = @pdf.bounds
|
|
93
|
+
|
|
94
|
+
@pdf.bounding_box [100,500] do
|
|
95
|
+
#nothing
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
@pdf.bounds.should == margin_box
|
|
99
|
+
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should restore the parent bounding box when calls are nested" do
|
|
103
|
+
@pdf.bounding_box [100,500], :width => 300, :height => 300 do
|
|
104
|
+
|
|
105
|
+
@pdf.bounds.absolute_top.should == 500 + @pdf.margin_box.absolute_bottom
|
|
106
|
+
@pdf.bounds.absolute_left.should == 100 + @pdf.margin_box.absolute_left
|
|
107
|
+
|
|
108
|
+
parent_box = @pdf.bounds
|
|
109
|
+
|
|
110
|
+
@pdf.bounding_box [50,200], :width => 100, :height => 100 do
|
|
111
|
+
@pdf.bounds.absolute_top.should == 200 + parent_box.absolute_bottom
|
|
112
|
+
@pdf.bounds.absolute_left.should == 50 + parent_box.absolute_left
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
@pdf.bounds.absolute_top.should == 500 + @pdf.margin_box.absolute_bottom
|
|
116
|
+
@pdf.bounds.absolute_left.should == 100 + @pdf.margin_box.absolute_left
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
it "should calculate a height if none is specified" do
|
|
122
|
+
@pdf.bounding_box([100, 500], :width => 100) do
|
|
123
|
+
@pdf.text "The rain in Spain falls mainly on the plains."
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
@pdf.y.should.be.close 458.384, 0.001
|
|
127
|
+
end
|
|
128
|
+
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
describe "A canvas" do
|
|
132
|
+
before(:each) { create_pdf }
|
|
133
|
+
|
|
134
|
+
it "should use whatever the last set y position is" do
|
|
135
|
+
@pdf.canvas do
|
|
136
|
+
@pdf.bounding_box([100,500],:width => 200) { @pdf.move_down 50 }
|
|
137
|
+
end
|
|
138
|
+
@pdf.y.should == 450
|
|
139
|
+
end
|
|
140
|
+
end
|
|
141
|
+
|