alphasights-prawn 0.10.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.
- data/COPYING +340 -0
- data/HACKING +50 -0
- data/LICENSE +56 -0
- data/README +141 -0
- data/Rakefile +52 -0
- data/data/encodings/win_ansi.txt +29 -0
- 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/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/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/fractal.jpg +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/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/tru256.bmp +0 -0
- data/data/images/web-links.dat +1 -0
- 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/hexagon.pdf +61 -0
- data/data/pdfs/indirect_reference.pdf +86 -0
- data/data/pdfs/nested_pages.pdf +118 -0
- data/data/pdfs/resources_as_indirect_object.pdf +83 -0
- data/data/pdfs/two_hexagons.pdf +90 -0
- data/data/pdfs/version_1_6.pdf +61 -0
- data/data/shift_jis_text.txt +1 -0
- data/examples/bounding_box/bounding_boxes.rb +43 -0
- data/examples/bounding_box/indentation.rb +34 -0
- data/examples/bounding_box/russian_boxes.rb +36 -0
- data/examples/bounding_box/stretched_nesting.rb +67 -0
- data/examples/builder/simple.rb +28 -0
- data/examples/example_helper.rb +4 -0
- data/examples/general/background.rb +23 -0
- data/examples/general/canvas.rb +15 -0
- data/examples/general/context_sensitive_headers.rb +37 -0
- data/examples/general/float.rb +11 -0
- data/examples/general/margin.rb +36 -0
- data/examples/general/measurement_units.rb +51 -0
- data/examples/general/metadata-info.rb +16 -0
- data/examples/general/multi_page_layout.rb +18 -0
- data/examples/general/outlines.rb +50 -0
- data/examples/general/page_geometry.rb +31 -0
- data/examples/general/page_numbering.rb +15 -0
- data/examples/general/repeaters.rb +47 -0
- data/examples/general/stamp.rb +41 -0
- data/examples/general/templates.rb +13 -0
- data/examples/graphics/basic_images.rb +23 -0
- data/examples/graphics/chunkable.rb +38 -0
- data/examples/graphics/cmyk.rb +12 -0
- data/examples/graphics/curves.rb +11 -0
- data/examples/graphics/hexagon.rb +13 -0
- data/examples/graphics/image_fit.rb +15 -0
- data/examples/graphics/image_flow.rb +37 -0
- data/examples/graphics/image_position.rb +17 -0
- data/examples/graphics/line.rb +32 -0
- data/examples/graphics/png_types.rb +22 -0
- data/examples/graphics/polygons.rb +16 -0
- data/examples/graphics/remote_images.rb +12 -0
- data/examples/graphics/rounded_polygons.rb +19 -0
- data/examples/graphics/rounded_rectangle.rb +20 -0
- data/examples/graphics/ruport_style_helpers.rb +19 -0
- data/examples/graphics/stroke_bounds.rb +20 -0
- data/examples/graphics/stroke_cap_and_join.rb +45 -0
- data/examples/graphics/stroke_dash.rb +42 -0
- data/examples/graphics/transformations.rb +52 -0
- data/examples/graphics/transparency.rb +26 -0
- data/examples/m17n/chinese_text_wrapping.rb +17 -0
- data/examples/m17n/euro.rb +15 -0
- data/examples/m17n/sjis.rb +28 -0
- data/examples/m17n/utf8.rb +13 -0
- data/examples/m17n/win_ansi_charset.rb +54 -0
- data/examples/security/hello_foo.rb +8 -0
- data/examples/table/bill.rb +53 -0
- data/examples/table/cell.rb +12 -0
- data/examples/table/checkerboard.rb +22 -0
- data/examples/table/header.rb +14 -0
- data/examples/table/inline_format_table.rb +12 -0
- data/examples/table/multi_page_table.rb +9 -0
- data/examples/table/simple_table.rb +24 -0
- data/examples/table/subtable.rb +12 -0
- data/examples/table/widths.rb +20 -0
- data/examples/text/alignment.rb +18 -0
- data/examples/text/character_spacing.rb +12 -0
- data/examples/text/dfont.rb +48 -0
- data/examples/text/family_based_styling.rb +24 -0
- data/examples/text/font_calculations.rb +91 -0
- data/examples/text/font_size.rb +33 -0
- data/examples/text/hyphenation.rb +45 -0
- data/examples/text/indent_paragraphs.rb +22 -0
- data/examples/text/inline_format.rb +103 -0
- data/examples/text/kerning.rb +30 -0
- data/examples/text/rotated.rb +98 -0
- data/examples/text/shaped_text_box.rb +31 -0
- data/examples/text/simple_text.rb +17 -0
- data/examples/text/simple_text_ttf.rb +17 -0
- data/examples/text/text_box.rb +88 -0
- data/examples/text/text_box_returning_excess.rb +51 -0
- data/examples/text/text_flow.rb +67 -0
- data/lib/prawn.rb +27 -0
- data/lib/prawn/canvas.rb +119 -0
- data/lib/prawn/chunkable.rb +37 -0
- 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/chunk.rb +36 -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 +165 -0
- data/lib/prawn/core/object_store.rb +236 -0
- data/lib/prawn/core/page.rb +179 -0
- data/lib/prawn/core/pdf_object.rb +108 -0
- data/lib/prawn/core/reference.rb +112 -0
- data/lib/prawn/core/text.rb +140 -0
- data/lib/prawn/core/text/formatted/arranger.rb +266 -0
- data/lib/prawn/core/text/formatted/line_wrap.rb +127 -0
- data/lib/prawn/core/text/formatted/wrap.rb +112 -0
- data/lib/prawn/core/text/line_wrap.rb +209 -0
- data/lib/prawn/core/text/wrap.rb +80 -0
- data/lib/prawn/document.rb +573 -0
- data/lib/prawn/document/bounding_box.rb +425 -0
- data/lib/prawn/document/graphics_state.rb +48 -0
- data/lib/prawn/document/internals.rb +170 -0
- data/lib/prawn/document/page_geometry.rb +136 -0
- data/lib/prawn/document/snapshot.rb +87 -0
- data/lib/prawn/document_builder.rb +51 -0
- data/lib/prawn/document_builder/command.rb +38 -0
- data/lib/prawn/document_builder/constructs.rb +2 -0
- data/lib/prawn/document_builder/constructs/flowing_text_construct.rb +18 -0
- data/lib/prawn/document_builder/constructs/path_construct.rb +9 -0
- data/lib/prawn/document_builder/layout.rb +25 -0
- data/lib/prawn/document_builder/modifications.rb +2 -0
- data/lib/prawn/document_builder/modifications/layout_modification.rb +9 -0
- data/lib/prawn/document_builder/modifications/path_modification.rb +9 -0
- data/lib/prawn/encoding.rb +121 -0
- data/lib/prawn/errors.rb +94 -0
- data/lib/prawn/font.rb +341 -0
- data/lib/prawn/font/afm.rb +225 -0
- data/lib/prawn/font/dfont.rb +42 -0
- data/lib/prawn/font/ttf.rb +350 -0
- data/lib/prawn/graphics.rb +325 -0
- data/lib/prawn/graphics/cap_style.rb +38 -0
- data/lib/prawn/graphics/color.rb +205 -0
- data/lib/prawn/graphics/dash.rb +71 -0
- data/lib/prawn/graphics/join_style.rb +38 -0
- data/lib/prawn/graphics/transformation.rb +156 -0
- data/lib/prawn/graphics/transparency.rb +99 -0
- data/lib/prawn/images.rb +348 -0
- data/lib/prawn/images/jpg.rb +46 -0
- data/lib/prawn/images/png.rb +226 -0
- data/lib/prawn/measurement_extensions.rb +46 -0
- data/lib/prawn/measurements.rb +71 -0
- data/lib/prawn/outline.rb +278 -0
- data/lib/prawn/repeater.rb +129 -0
- data/lib/prawn/security.rb +262 -0
- data/lib/prawn/security/arcfour.rb +51 -0
- data/lib/prawn/stamp.rb +126 -0
- data/lib/prawn/table.rb +421 -0
- data/lib/prawn/table/accessors.rb +180 -0
- data/lib/prawn/table/cell.rb +350 -0
- data/lib/prawn/table/cell/in_table.rb +27 -0
- data/lib/prawn/table/cell/subtable.rb +65 -0
- data/lib/prawn/table/cell/text.rb +125 -0
- data/lib/prawn/text.rb +449 -0
- data/lib/prawn/text/box.rb +392 -0
- data/lib/prawn/text/formatted.rb +4 -0
- data/lib/prawn/text/formatted/box.rb +228 -0
- data/lib/prawn/text/formatted/fragment.rb +181 -0
- data/lib/prawn/text/formatted/parser.rb +213 -0
- data/spec/annotations_spec.rb +90 -0
- data/spec/bounding_box_spec.rb +190 -0
- data/spec/cell_spec.rb +348 -0
- data/spec/destinations_spec.rb +15 -0
- data/spec/document_spec.rb +473 -0
- data/spec/font_spec.rb +324 -0
- data/spec/formatted_text_arranger_spec.rb +426 -0
- data/spec/formatted_text_box_spec.rb +756 -0
- data/spec/formatted_text_fragment_spec.rb +211 -0
- data/spec/graphics_spec.rb +446 -0
- data/spec/images_spec.rb +96 -0
- data/spec/inline_formatted_text_parser_spec.rb +502 -0
- data/spec/jpg_spec.rb +25 -0
- data/spec/line_wrap_spec.rb +341 -0
- data/spec/measurement_units_spec.rb +23 -0
- data/spec/name_tree_spec.rb +112 -0
- data/spec/object_store_spec.rb +160 -0
- data/spec/outline_spec.rb +269 -0
- data/spec/pdf_object_spec.rb +170 -0
- data/spec/png_spec.rb +237 -0
- data/spec/reference_spec.rb +82 -0
- data/spec/repeater_spec.rb +96 -0
- data/spec/security_spec.rb +120 -0
- data/spec/snapshot_spec.rb +138 -0
- data/spec/spec_helper.rb +26 -0
- data/spec/stamp_spec.rb +108 -0
- data/spec/stroke_styles_spec.rb +163 -0
- data/spec/table_spec.rb +598 -0
- data/spec/template_spec.rb +158 -0
- data/spec/text_at_spec.rb +119 -0
- data/spec/text_box_spec.rb +742 -0
- data/spec/text_spacing_spec.rb +75 -0
- data/spec/text_spec.rb +333 -0
- data/spec/text_with_inline_formatting_spec.rb +193 -0
- data/spec/transparency_spec.rb +89 -0
- metadata +331 -0
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
|
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
|
4
|
+
|
|
5
|
+
describe "Prawn::ObjectStore" do
|
|
6
|
+
before(:each) do
|
|
7
|
+
@store = Prawn::Core::ObjectStore.new
|
|
8
|
+
end
|
|
9
|
+
|
|
10
|
+
it "should create required roots by default, including info passed to new" do
|
|
11
|
+
store = Prawn::Core::ObjectStore.new(:info => {:Test => 3})
|
|
12
|
+
store.size.should == 3 # 3 default roots
|
|
13
|
+
store.info.data[:Test].should == 3
|
|
14
|
+
store.pages.data[:Count].should == 0
|
|
15
|
+
store.root.data[:Pages].should == store.pages
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "should import objects from an existing PDF" do
|
|
19
|
+
filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
|
|
20
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
21
|
+
store.size.should == 5
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
it "should point to existing roots when importing objects from an existing PDF" do
|
|
25
|
+
filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
|
|
26
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
27
|
+
store.info.class.should == Prawn::Core::Reference
|
|
28
|
+
store.root.class.should == Prawn::Core::Reference
|
|
29
|
+
end
|
|
30
|
+
|
|
31
|
+
it "should initialize with pages when importing objects from an existing PDF" do
|
|
32
|
+
filename = "#{Prawn::BASEDIR}/reference_pdfs/curves.pdf"
|
|
33
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
34
|
+
store.pages.data[:Count].should == 1
|
|
35
|
+
end
|
|
36
|
+
|
|
37
|
+
it "should import all objects from a PDF that has an indirect reference in a stream dict" do
|
|
38
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/indirect_reference.pdf"
|
|
39
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
40
|
+
store.size.should == 8
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
it "should raise ArgumentError when given a file that doesn exist as a template" do
|
|
44
|
+
filename = "not_really_there.pdf"
|
|
45
|
+
|
|
46
|
+
lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(ArgumentError)
|
|
47
|
+
end
|
|
48
|
+
|
|
49
|
+
it "should raise Prawn::Errors::TemplateError when given a non PDF as a template" do
|
|
50
|
+
filename = "#{Prawn::BASEDIR}/data/images/dice.png"
|
|
51
|
+
|
|
52
|
+
lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(Prawn::Errors::TemplateError)
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should raise Prawn::Errors::TemplateError when given an encrypted PDF as a template" do
|
|
56
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/encrypted.pdf"
|
|
57
|
+
|
|
58
|
+
lambda { Prawn::Core::ObjectStore.new(:template => filename) }.should.raise(Prawn::Errors::TemplateError)
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
it "should add to its objects when ref() is called" do
|
|
62
|
+
count = @store.size
|
|
63
|
+
@store.ref("blah")
|
|
64
|
+
@store.size.should == count + 1
|
|
65
|
+
end
|
|
66
|
+
|
|
67
|
+
it "should accept push with a Prawn::Reference" do
|
|
68
|
+
r = Prawn::Core::Reference(123, "blah")
|
|
69
|
+
@store.push(r)
|
|
70
|
+
@store[r.identifier].should == r
|
|
71
|
+
end
|
|
72
|
+
|
|
73
|
+
it "should accept arbitrary data and use it to create a Prawn::Reference" do
|
|
74
|
+
@store.push(123, "blahblah")
|
|
75
|
+
@store[123].data.should == "blahblah"
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
it "should be Enumerable, yielding in order of submission" do
|
|
79
|
+
# higher IDs to bypass the default roots
|
|
80
|
+
[10, 11, 12].each do |id|
|
|
81
|
+
@store.push(id, "some data #{id}")
|
|
82
|
+
end
|
|
83
|
+
@store.map{|ref| ref.identifier}[-3..-1].should == [10, 11, 12]
|
|
84
|
+
end
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
describe "Prawn::ObjectStore#compact" do
|
|
88
|
+
it "should do nothing to an ObjectStore with all live refs" do
|
|
89
|
+
store = Prawn::Core::ObjectStore.new
|
|
90
|
+
store.info.data[:Blah] = store.ref(:some => "structure")
|
|
91
|
+
old_size = store.size
|
|
92
|
+
store.compact
|
|
93
|
+
|
|
94
|
+
store.size.should == old_size
|
|
95
|
+
end
|
|
96
|
+
|
|
97
|
+
it "should remove dead objects, renumbering live objects from 1" do
|
|
98
|
+
store = Prawn::Core::ObjectStore.new
|
|
99
|
+
store.ref(:some => "structure")
|
|
100
|
+
old_size = store.size
|
|
101
|
+
store.compact
|
|
102
|
+
|
|
103
|
+
store.size.should.be < old_size
|
|
104
|
+
store.map{ |o| o.identifier }.should == (1..store.size).to_a
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
it "should detect and remove dead objects that were once live" do
|
|
108
|
+
store = Prawn::Core::ObjectStore.new
|
|
109
|
+
store.info.data[:Blah] = store.ref(:some => "structure")
|
|
110
|
+
store.info.data[:Blah] = :overwritten
|
|
111
|
+
old_size = store.size
|
|
112
|
+
store.compact
|
|
113
|
+
|
|
114
|
+
store.size.should.be < old_size
|
|
115
|
+
store.map{ |o| o.identifier }.should == (1..store.size).to_a
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
describe "Prawn::ObjectStorie#object_id_for_page" do
|
|
120
|
+
it "should return the object ID of an imported template page" do
|
|
121
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
|
|
122
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
123
|
+
store.object_id_for_page(0).should == 4
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
it "should return the object ID of the first imported template page" do
|
|
127
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/two_hexagons.pdf"
|
|
128
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
129
|
+
store.object_id_for_page(1).should == 4
|
|
130
|
+
end
|
|
131
|
+
|
|
132
|
+
it "should return the object ID of the last imported template page" do
|
|
133
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/two_hexagons.pdf"
|
|
134
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
135
|
+
store.object_id_for_page(-1).should == 6
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "should return the object ID of the first page of a template that uses nested Pages" do
|
|
139
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/nested_pages.pdf"
|
|
140
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
141
|
+
store.object_id_for_page(1).should == 5
|
|
142
|
+
end
|
|
143
|
+
|
|
144
|
+
it "should return the object ID of the last page of a template that uses nested Pages" do
|
|
145
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/nested_pages.pdf"
|
|
146
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
147
|
+
store.object_id_for_page(-1).should == 8
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
it "should return nil if given an invalid page number" do
|
|
151
|
+
filename = "#{Prawn::BASEDIR}/data/pdfs/hexagon.pdf"
|
|
152
|
+
store = Prawn::Core::ObjectStore.new(:template => filename)
|
|
153
|
+
store.object_id_for_page(10).should == nil
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
it "should return nil if given an invalid page number" do
|
|
157
|
+
store = Prawn::Core::ObjectStore.new
|
|
158
|
+
store.object_id_for_page(10).should == nil
|
|
159
|
+
end
|
|
160
|
+
end
|
|
@@ -0,0 +1,269 @@
|
|
|
1
|
+
# encoding: utf-8
|
|
2
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
|
3
|
+
|
|
4
|
+
describe "Outline" do
|
|
5
|
+
before(:each) do
|
|
6
|
+
@pdf = Prawn::Document.new() do
|
|
7
|
+
text "Page 1. This is the first Chapter. "
|
|
8
|
+
start_new_page
|
|
9
|
+
text "Page 2. More in the first Chapter. "
|
|
10
|
+
start_new_page
|
|
11
|
+
define_outline do
|
|
12
|
+
section 'Chapter 1', :page => 1, :closed => true do
|
|
13
|
+
page 1, :title => 'Page 1'
|
|
14
|
+
page 2, :title => 'Page 2'
|
|
15
|
+
end
|
|
16
|
+
end
|
|
17
|
+
end
|
|
18
|
+
end
|
|
19
|
+
if RUBY_VERSION >= "1.9"
|
|
20
|
+
describe "outline encoding" do
|
|
21
|
+
it "should store all outline titles as UTF-16" do
|
|
22
|
+
render_and_find_objects
|
|
23
|
+
@hash.values.each do |obj|
|
|
24
|
+
if obj.is_a?(Hash) && obj[:Title]
|
|
25
|
+
title = obj[:Title].dup
|
|
26
|
+
title.force_encoding("UTF-16LE")
|
|
27
|
+
title.valid_encoding?.should == true
|
|
28
|
+
end
|
|
29
|
+
end
|
|
30
|
+
end
|
|
31
|
+
end
|
|
32
|
+
end
|
|
33
|
+
describe "#generate_outline" do
|
|
34
|
+
before(:each) do
|
|
35
|
+
render_and_find_objects
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should create a root outline dictionary item" do
|
|
39
|
+
assert_not_nil @outline_root
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
it "should set the first and last top items of the root outline dictionary item" do
|
|
43
|
+
referenced_object(@outline_root[:First]).should == @section_1
|
|
44
|
+
referenced_object(@outline_root[:Last]).should == @section_1
|
|
45
|
+
end
|
|
46
|
+
|
|
47
|
+
describe "#create_outline_item" do
|
|
48
|
+
it "should create outline items for each section and page" do
|
|
49
|
+
[@section_1, @page_1, @page_2].each {|item| assert_not_nil item}
|
|
50
|
+
end
|
|
51
|
+
end
|
|
52
|
+
|
|
53
|
+
describe "#set_relations, #set_variables_for_block, and #reset_parent" do
|
|
54
|
+
it "should link sibling items" do
|
|
55
|
+
referenced_object(@page_1[:Next]).should == @page_2
|
|
56
|
+
referenced_object(@page_2[:Prev]).should == @page_1
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
it "should link child items to parent item" do
|
|
60
|
+
[@page_1, @page_2].each {|page| referenced_object(page[:Parent]).should == @section_1 }
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
it "should set the first and last child items for parent item" do
|
|
64
|
+
referenced_object(@section_1[:First]).should == @page_1
|
|
65
|
+
referenced_object(@section_1[:Last]).should == @page_2
|
|
66
|
+
end
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
describe "#increase_count" do
|
|
70
|
+
|
|
71
|
+
it "should add the count of all descendant items" do
|
|
72
|
+
@outline_root[:Count].should == 3
|
|
73
|
+
@section_1[:Count].should.abs == 2
|
|
74
|
+
@page_1[:Count].should == 0
|
|
75
|
+
@page_2[:Count].should == 0
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
end
|
|
79
|
+
|
|
80
|
+
describe "closed option" do
|
|
81
|
+
|
|
82
|
+
it "should set the item's integer count to negative" do
|
|
83
|
+
@section_1[:Count].should == -2
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
describe "#outline.add_section" do
|
|
91
|
+
before(:each) do
|
|
92
|
+
@pdf.start_new_page
|
|
93
|
+
@pdf.text "Page 3. An added section "
|
|
94
|
+
@pdf.outline.add_section do
|
|
95
|
+
section 'Added Section', :page => 3 do
|
|
96
|
+
page 3, :title => 'Page 3'
|
|
97
|
+
end
|
|
98
|
+
end
|
|
99
|
+
render_and_find_objects
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should add new outline items to document" do
|
|
103
|
+
[@section_2, @page_3].each { |item| assert_not_nil item}
|
|
104
|
+
end
|
|
105
|
+
|
|
106
|
+
it "should reset the last items for root outline dictionary" do
|
|
107
|
+
referenced_object(@outline_root[:First]).should == @section_1
|
|
108
|
+
referenced_object(@outline_root[:Last]).should == @section_2
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
it "should reset the next relation for the previous last top level item" do
|
|
112
|
+
referenced_object(@section_1[:Next]).should == @section_2
|
|
113
|
+
end
|
|
114
|
+
|
|
115
|
+
it "should set the previous relation of the addded to section" do
|
|
116
|
+
referenced_object(@section_2[:Prev]).should == @section_1
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
it "should increase the count of root outline dictionary" do
|
|
120
|
+
@outline_root[:Count].should == 5
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
describe "#outline.insert_section_after" do
|
|
126
|
+
describe "inserting in the middle of another section" do
|
|
127
|
+
before(:each) do
|
|
128
|
+
@pdf.go_to_page 1
|
|
129
|
+
@pdf.start_new_page
|
|
130
|
+
@pdf.text "Inserted Page"
|
|
131
|
+
@pdf.outline.insert_section_after 'Page 1' do
|
|
132
|
+
page page_number, :title => "Inserted Page"
|
|
133
|
+
end
|
|
134
|
+
render_and_find_objects
|
|
135
|
+
end
|
|
136
|
+
|
|
137
|
+
it "should insert new outline items to document" do
|
|
138
|
+
assert_not_nil @inserted_page
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
it "should adjust the count of all ancestors" do
|
|
142
|
+
@outline_root[:Count].should == 4
|
|
143
|
+
@section_1[:Count].should.abs == 3
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
describe "#adjust_relations" do
|
|
147
|
+
|
|
148
|
+
it "should reset the sibling relations of adjoining items to inserted item" do
|
|
149
|
+
referenced_object(@page_1[:Next]).should == @inserted_page
|
|
150
|
+
referenced_object(@page_2[:Prev]).should == @inserted_page
|
|
151
|
+
end
|
|
152
|
+
|
|
153
|
+
it "should set the sibling relation of added item to adjoining items" do
|
|
154
|
+
referenced_object(@inserted_page[:Next]).should == @page_2
|
|
155
|
+
referenced_object(@inserted_page[:Prev]).should == @page_1
|
|
156
|
+
end
|
|
157
|
+
|
|
158
|
+
it "should not affect the first and last relations of parent item" do
|
|
159
|
+
referenced_object(@section_1[:First]).should == @page_1
|
|
160
|
+
referenced_object(@section_1[:Last]).should == @page_2
|
|
161
|
+
end
|
|
162
|
+
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
describe "inserting at the end of another section" do
|
|
168
|
+
before(:each) do
|
|
169
|
+
@pdf.go_to_page 2
|
|
170
|
+
@pdf.start_new_page
|
|
171
|
+
@pdf.text "Inserted Page"
|
|
172
|
+
@pdf.outline.insert_section_after 'Page 2' do
|
|
173
|
+
page page_number, :title => "Inserted Page"
|
|
174
|
+
end
|
|
175
|
+
render_and_find_objects
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
describe "#adjust_relations" do
|
|
179
|
+
|
|
180
|
+
it "should reset the sibling relations of adjoining item to inserted item" do
|
|
181
|
+
referenced_object(@page_2[:Next]).should == @inserted_page
|
|
182
|
+
end
|
|
183
|
+
|
|
184
|
+
it "should set the sibling relation of added item to adjoining items" do
|
|
185
|
+
assert_nil referenced_object(@inserted_page[:Next])
|
|
186
|
+
referenced_object(@inserted_page[:Prev]).should == @page_2
|
|
187
|
+
end
|
|
188
|
+
|
|
189
|
+
it "should adjust the last relation of parent item" do
|
|
190
|
+
referenced_object(@section_1[:Last]).should == @inserted_page
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
end
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
it "should require an existing title" do
|
|
197
|
+
assert_raise Prawn::Errors::UnknownOutlineTitle do
|
|
198
|
+
@pdf.go_to_page 1
|
|
199
|
+
@pdf.start_new_page
|
|
200
|
+
@pdf.text "Inserted Page"
|
|
201
|
+
@pdf.outline.insert_section_after 'Wrong page' do
|
|
202
|
+
page page_number, :title => "Inserted Page"
|
|
203
|
+
end
|
|
204
|
+
render_and_find_objects
|
|
205
|
+
end
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
describe "#page" do
|
|
211
|
+
it "should require a title option to be set" do
|
|
212
|
+
assert_raise Prawn::Errors::RequiredOption do
|
|
213
|
+
@pdf = Prawn::Document.new() do
|
|
214
|
+
text "Page 1. This is the first Chapter. "
|
|
215
|
+
define_outline do
|
|
216
|
+
page 1, :title => nil
|
|
217
|
+
end
|
|
218
|
+
end
|
|
219
|
+
end
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context "foreign character encoding" do
|
|
225
|
+
before(:each) do
|
|
226
|
+
pdf = Prawn::Document.new() do
|
|
227
|
+
define_outline do
|
|
228
|
+
section 'La pomme croquée', :page => 1, :closed => true
|
|
229
|
+
end
|
|
230
|
+
end
|
|
231
|
+
@hash = PDF::Hash.new(StringIO.new(pdf.render, 'r+'))
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
it "should handle other encodings for the title" do
|
|
235
|
+
object = find_by_title('La pomme croquée')
|
|
236
|
+
object.should.not == nil
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
def render_and_find_objects
|
|
241
|
+
output = StringIO.new(@pdf.render, 'r+')
|
|
242
|
+
@hash = PDF::Hash.new(output)
|
|
243
|
+
@outline_root = @hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Outlines}
|
|
244
|
+
@pages = @hash.values.find {|obj| obj.is_a?(Hash) && obj[:Type] == :Pages}[:Kids]
|
|
245
|
+
@section_1 = find_by_title('Chapter 1')
|
|
246
|
+
@page_1 = find_by_title('Page 1')
|
|
247
|
+
@page_2 = find_by_title('Page 2')
|
|
248
|
+
@section_2 = find_by_title('Added Section')
|
|
249
|
+
@page_3 = find_by_title('Page 3')
|
|
250
|
+
@inserted_page = find_by_title('Inserted Page')
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
# Outline titles are stored as UTF-16. This method accepts a UTF-8 outline title
|
|
254
|
+
# and returns the PDF Object that contains an outline with that name
|
|
255
|
+
def find_by_title(title)
|
|
256
|
+
@hash.values.find {|obj|
|
|
257
|
+
if obj.is_a?(Hash) && obj[:Title]
|
|
258
|
+
title_codepoints = obj[:Title].unpack("n*")
|
|
259
|
+
title_codepoints.shift
|
|
260
|
+
utf8_title = title_codepoints.pack("U*")
|
|
261
|
+
utf8_title == title ? obj : nil
|
|
262
|
+
end
|
|
263
|
+
}
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
def referenced_object(reference)
|
|
267
|
+
@hash[reference]
|
|
268
|
+
end
|
|
269
|
+
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
# encoding: ASCII-8BIT
|
|
2
|
+
|
|
3
|
+
require File.join(File.expand_path(File.dirname(__FILE__)), "spec_helper")
|
|
4
|
+
|
|
5
|
+
# See PDF Reference, Sixth Edition (1.7) pp51-60 for details
|
|
6
|
+
describe "PDF Object Serialization" do
|
|
7
|
+
|
|
8
|
+
it "should convert Ruby's nil to PDF null" do
|
|
9
|
+
Prawn::Core::PdfObject(nil).should == "null"
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
it "should convert Ruby booleans to PDF booleans" do
|
|
13
|
+
Prawn::Core::PdfObject(true).should == "true"
|
|
14
|
+
Prawn::Core::PdfObject(false).should == "false"
|
|
15
|
+
end
|
|
16
|
+
|
|
17
|
+
it "should convert a Ruby number to PDF number" do
|
|
18
|
+
Prawn::Core::PdfObject(1).should == "1"
|
|
19
|
+
Prawn::Core::PdfObject(1.214112421).should == "1.214112421"
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "should convert a Ruby time object to a PDF timestamp" do
|
|
23
|
+
t = Time.now
|
|
24
|
+
Prawn::Core::PdfObject(t).should == t.strftime("(D:%Y%m%d%H%M%S%z").chop.chop + "'00')"
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
it "should convert a Ruby string to PDF string when inside a content stream" do
|
|
28
|
+
s = "I can has a string"
|
|
29
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
it "should convert a Ruby string to a UTF-16 PDF string when outside a content stream" do
|
|
33
|
+
s = "I can has a string"
|
|
34
|
+
s_utf16 = "\xFE\xFF" + s.unpack("U*").pack("n*")
|
|
35
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject(s, false)).should == s_utf16
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
it "should convert a Ruby string with characters outside the BMP to its " +
|
|
39
|
+
"UTF-16 representation with a BOM" do
|
|
40
|
+
# U+10192 ROMAN SEMUNCIA SIGN
|
|
41
|
+
semuncia = [65938].pack("U")
|
|
42
|
+
Prawn::Core::PdfObject(semuncia, false).upcase.should == "<FEFFD800DD92>"
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
it "should pass through bytes regardless of content stream status for ByteString" do
|
|
46
|
+
Prawn::Core::PdfObject(Prawn::Core::ByteString.new("\xDE\xAD\xBE\xEF")).upcase.
|
|
47
|
+
should == "<DEADBEEF>"
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
it "should escape parens when converting from Ruby string to PDF" do
|
|
51
|
+
s = 'I )(can has a string'
|
|
52
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
it "should handle ruby escaped parens when converting to PDF string" do
|
|
56
|
+
s = 'I can \\)( has string'
|
|
57
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject(s, true)).should == s
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
it "should escape various strings correctly when converting a LiteralString" do
|
|
61
|
+
ls = Prawn::Core::LiteralString.new("abc")
|
|
62
|
+
Prawn::Core::PdfObject(ls).should == "(abc)"
|
|
63
|
+
|
|
64
|
+
ls = Prawn::Core::LiteralString.new("abc\x0Ade") # should escape \n
|
|
65
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Ade)"
|
|
66
|
+
|
|
67
|
+
ls = Prawn::Core::LiteralString.new("abc\x0Dde") # should escape \r
|
|
68
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Dde)"
|
|
69
|
+
|
|
70
|
+
ls = Prawn::Core::LiteralString.new("abc\x09de") # should escape \t
|
|
71
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x09de)"
|
|
72
|
+
|
|
73
|
+
ls = Prawn::Core::LiteralString.new("abc\x08de") # should escape \b
|
|
74
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x08de)"
|
|
75
|
+
|
|
76
|
+
ls = Prawn::Core::LiteralString.new("abc\x0Cde") # should escape \f
|
|
77
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x0Cde)"
|
|
78
|
+
|
|
79
|
+
ls = Prawn::Core::LiteralString.new("abc(de") # should escape \(
|
|
80
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C(de)"
|
|
81
|
+
|
|
82
|
+
ls = Prawn::Core::LiteralString.new("abc)de") # should escape \)
|
|
83
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C)de)"
|
|
84
|
+
|
|
85
|
+
ls = Prawn::Core::LiteralString.new("abc\x5Cde") # should escape \\
|
|
86
|
+
Prawn::Core::PdfObject(ls).should == "(abc\x5C\x5Cde)"
|
|
87
|
+
Prawn::Core::PdfObject(ls).size.should == 9
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
it "should escape strings correctly when converting a LiteralString that is not utf-8" do
|
|
91
|
+
data = "\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\xaf\xd0"
|
|
92
|
+
ls = Prawn::Core::LiteralString.new(data)
|
|
93
|
+
Prawn::Core::PdfObject(ls).should == "(\x43\xaf\xc9\x7f\xef\xf\xe6\xa8\xcb\x5c\x5c\xaf\xd0)"
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
it "should convert a Ruby symbol to PDF name" do
|
|
97
|
+
Prawn::Core::PdfObject(:my_symbol).should == "/my_symbol"
|
|
98
|
+
Prawn::Core::PdfObject(:"A;Name_With-Various***Characters?").should ==
|
|
99
|
+
"/A;Name_With-Various***Characters?"
|
|
100
|
+
end
|
|
101
|
+
|
|
102
|
+
it "should convert a whitespace or delimiter containing Ruby symbol to a PDF name" do
|
|
103
|
+
Prawn::Core::PdfObject(:"my symbol").should == "/my#20symbol"
|
|
104
|
+
Prawn::Core::PdfObject(:"my#symbol").should == "/my#23symbol"
|
|
105
|
+
Prawn::Core::PdfObject(:"my/symbol").should == "/my#2Fsymbol"
|
|
106
|
+
Prawn::Core::PdfObject(:"my(symbol").should == "/my#28symbol"
|
|
107
|
+
Prawn::Core::PdfObject(:"my)symbol").should == "/my#29symbol"
|
|
108
|
+
Prawn::Core::PdfObject(:"my<symbol").should == "/my#3Csymbol"
|
|
109
|
+
Prawn::Core::PdfObject(:"my>symbol").should == "/my#3Esymbol"
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
it "should convert a Ruby array to PDF Array when inside a content stream" do
|
|
113
|
+
Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
|
|
114
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], true)).should ==
|
|
115
|
+
[[1,2],:foo, "Bar"]
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
it "should convert a Ruby array to PDF Array when outside a content stream" do
|
|
119
|
+
bar = "\xFE\xFF" + "Bar".unpack("U*").pack("n*")
|
|
120
|
+
Prawn::Core::PdfObject([1,2,3]).should == "[1 2 3]"
|
|
121
|
+
PDF::Inspector.parse(Prawn::Core::PdfObject([[1,2],:foo,"Bar"], false)).should ==
|
|
122
|
+
[[1,2],:foo, bar]
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
it "should convert a Ruby hash to a PDF Dictionary when inside a content stream" do
|
|
126
|
+
dict = Prawn::Core::PdfObject( {:foo => :bar,
|
|
127
|
+
"baz" => [1,2,3],
|
|
128
|
+
:bang => {:a => "what", :b => [:you, :say] }}, true )
|
|
129
|
+
|
|
130
|
+
res = PDF::Inspector.parse(dict)
|
|
131
|
+
|
|
132
|
+
res[:foo].should == :bar
|
|
133
|
+
res[:baz].should == [1,2,3]
|
|
134
|
+
res[:bang].should == { :a => "what", :b => [:you, :say] }
|
|
135
|
+
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
it "should convert a Ruby hash to a PDF Dictionary when outside a content stream" do
|
|
139
|
+
what = "\xFE\xFF" + "what".unpack("U*").pack("n*")
|
|
140
|
+
dict = Prawn::Core::PdfObject( {:foo => :bar,
|
|
141
|
+
"baz" => [1,2,3],
|
|
142
|
+
:bang => {:a => "what", :b => [:you, :say] }}, false )
|
|
143
|
+
|
|
144
|
+
res = PDF::Inspector.parse(dict)
|
|
145
|
+
|
|
146
|
+
res[:foo].should == :bar
|
|
147
|
+
res[:baz].should == [1,2,3]
|
|
148
|
+
res[:bang].should == { :a => what, :b => [:you, :say] }
|
|
149
|
+
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
it "should not allow keys other than strings or symbols for PDF dicts" do
|
|
153
|
+
lambda { Prawn::Core::PdfObject(:foo => :bar, :baz => :bang, 1 => 4) }.
|
|
154
|
+
should.raise(Prawn::Errors::FailedObjectConversion)
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
it "should convert a Prawn::Reference to a PDF indirect object reference" do
|
|
158
|
+
ref = Prawn::Core::Reference(1,true)
|
|
159
|
+
Prawn::Core::PdfObject(ref).should == ref.to_s
|
|
160
|
+
end
|
|
161
|
+
|
|
162
|
+
it "should convert a NameTree::Node to a PDF hash" do
|
|
163
|
+
node = Prawn::Core::NameTree::Node.new(Prawn::Document.new, 10)
|
|
164
|
+
node.add "hello", 1.0
|
|
165
|
+
node.add "world", 2.0
|
|
166
|
+
data = Prawn::Core::PdfObject(node)
|
|
167
|
+
res = PDF::Inspector.parse(data)
|
|
168
|
+
res.should == {:Names => ["hello", 1.0, "world", 2.0]}
|
|
169
|
+
end
|
|
170
|
+
end
|