jpdfer 0.3.1-java → 0.4.0-java

Sign up to get free protection for your applications and to get access to all the features.
data/lib/jpdfer/pdf.rb CHANGED
@@ -34,67 +34,98 @@ module Jpdfer
34
34
  descriptions.count > 0 ? descriptions.first.text : ""
35
35
  end
36
36
 
37
- def self.open(pdf_path, save_path, options={})
37
+ # A convenience method which concatenates the pages of several pdfs into one pdf. If a block is given,
38
+ # the new pdf is yielded and saved to +save_path+ after the block has been called.
39
+ #
40
+ # The available options are :keystore and :flatten.
41
+ #
42
+ # Returns the created pdf. If no block is given, save_as must be called to save the pdf.
43
+ def self.concatenate(pdfs, save_path=nil, options={})
44
+ output_buffer = StringIO.new
38
45
  flatten = options.delete(:flatten)
39
- pdf = self.new(pdf_path, options)
46
+ concatenator = PdfCopyFields.new output_buffer.to_outputstream
47
+
48
+ pdfs.each do |pdf|
49
+ concatenator.addDocument pdf.reader
50
+ end
51
+ concatenator.close
52
+
53
+ pdf = new(StringIO.new(output_buffer.string), options)
40
54
  if block_given?
41
55
  yield pdf
42
56
  pdf.save_as(save_path, flatten)
43
- else
44
- pdf
45
57
  end
58
+ pdf
59
+ end
60
+
61
+ # A convenience method which initializes a new pdf. If a block is given,
62
+ # the new pdf is yielded and saved to +save_path+ after the block has been called.
63
+ #
64
+ # The options accept :flatten and :keystore.
65
+ #
66
+ # Returns the created pdf. If no block is given, save_as must be called to save the pdf.
67
+ def self.open(pdf_path, save_path=nil, options={})
68
+ flatten = options.delete(:flatten)
69
+ pdf = new(pdf_path, options)
70
+ if block_given?
71
+ yield pdf
72
+ pdf.save_as(save_path, flatten)
73
+ end
74
+ pdf
46
75
  end
47
76
 
48
77
  # Currently the only option is :keystore
49
- def initialize(path, options = {})
50
- @data = File.read(path)
51
- @output_buffer = StringIO.new
52
- reader = PdfReader.new(@data.to_java_bytes)
53
- @stamper = create_stamper(reader, options[:keystore])
54
- @saved = false
78
+ def initialize(file_or_path, options = {})
79
+ data = file_or_path.read if file_or_path.respond_to?(:read)
80
+ data ||= File.read file_or_path
81
+
82
+ @keystore = options[:keystore]
83
+
84
+ init(data)
55
85
  end
56
86
 
57
- # helper method for initialize not ment to be used publicly
58
- def create_stamper(reader, keystore = nil)
59
- if keystore
60
- stamper = PdfStamper.createSignature(reader, @output_buffer.to_outputstream, 0)
61
- key, certificate_chain = keystore.private_key, keystore.certificate_chain
62
- # TODO: Should not always be self-signed
63
- signature_type = Pdf::PdfSignatureAppearance::SELF_SIGNED
64
- stamper.getSignatureAppearance.setCrypto(key, certificate_chain, nil, signature_type)
65
- else
66
- stamper = PdfStamper.new(reader, @output_buffer.to_outputstream)
67
- end
68
- stamper
87
+ # Instances of Pdf forward any possible unknown method calls to the underlying
88
+ # iText PdfReader instance
89
+ def method_missing(method, *args)
90
+ return @reader.send(method, *args) if @reader.respond_to? method
91
+ super
92
+ end
93
+
94
+ # Returns an independent instance of the underlying iText PdfReader.
95
+ def reader
96
+ PdfReader.new @data.to_java_bytes
97
+ end
98
+
99
+ # Returns a string representation of the Pdf object
100
+ def inspect
101
+ "<Jpdfer::Pdf @reader=#{@reader}, @stamper=#{@stamper}>"
69
102
  end
70
103
 
71
104
  # Writes PDF to +path+. If +flatten+ is true, also flattens the form
72
105
  # so that the form is printed on the PDF document but the form is no
73
106
  # longer editable.
74
107
  #
75
- # Once a this has been called the PDF becomes read-only and any
76
- # subsequent calls to +save_as+, +set_field+, or +set_fields+
77
- # will raise an ReadOnlyError.
78
- #
79
108
  # save_as returns *UNTESTED* if the PDF form is not valid
80
109
  def save_as(path, flatten=false)
81
- raise ReadOnlyError.new("Cannot save a previously saved pdf") if @saved
82
- @saved = true
83
110
  if flatten
84
111
  metadata = self.class.create_flatten_fields_xml(fields)
85
112
  @stamper.setXmpMetadata metadata.to_java_bytes
86
113
  end
114
+
87
115
  @stamper.setFormFlattening(flatten)
88
116
  @stamper.close
117
+
89
118
  File.open(path, 'wb') do |file|
90
119
  file.write(@output_buffer.string)
91
120
  end
121
+
122
+ init(@output_buffer.string)
92
123
  end
93
124
 
94
125
  # Returns the page size of the pdf as [width (Float), height (Float)]
95
126
  def page_size
96
- page_size = @stamper.reader.crop_box(1)
97
- if @stamper.reader.page_rotation(1) % 180 == 0
127
+ page_size = @reader.crop_box(1)
128
+ if @reader.page_rotation(1) % 180 == 0
98
129
  [page_size.width, page_size.height]
99
130
  else
100
131
  [page_size.height, page_size.width]
@@ -111,11 +142,9 @@ module Jpdfer
111
142
  # fields returns an empty hash if PDF document does not contain a form
112
143
  def fields
113
144
  form = @stamper.getAcroFields
114
- h = {}
115
- form.getFields.each_pair do |name, value|
116
- h[name.to_sym] = form.getField(name)
145
+ form.getFields.each_with_object({}) do |(name, value), fields|
146
+ fields[name.to_sym] = form.getField(name)
117
147
  end
118
- h
119
148
  end
120
149
 
121
150
  # Returns value of named field.
@@ -129,10 +158,8 @@ module Jpdfer
129
158
 
130
159
  # Sets named field. set_field returns value set.
131
160
  #
132
- # Raises Pdf::NonexistentFieldError if field does not exist.
133
161
  # +name+: Symbol naming the field to write
134
162
  def set_field(name, value)
135
- raise ReadOnlyError.new('Previously saved pdfs are read-only') if @saved
136
163
  name = name.to_sym
137
164
  raise NonexistentFieldError.new("'#{name}' field does not exist in form") unless has_field?(name)
138
165
  @stamper.getAcroFields.setField(name.to_s, value.to_s)
@@ -142,7 +169,6 @@ module Jpdfer
142
169
  # Sets many fields at once. Returns the hash of fields set (should
143
170
  # always be equal to given set of fields).
144
171
  #
145
- # Raises Pdf::NonexistentFieldError if any field does not exist.
146
172
  # +fields+:: A hash of :key => "value" pairs.
147
173
  def set_fields(fields)
148
174
  fields.each_pair do |name, value|
@@ -167,20 +193,32 @@ module Jpdfer
167
193
  # form in this pdf before flattening.
168
194
  # Returns an empty hash if there are not any.
169
195
  def flattened_fields
170
- reader = @stamper.reader
171
- metadata_string = String.from_java_bytes reader.getMetadata
196
+ metadata_string = String.from_java_bytes @reader.getMetadata
172
197
  description_text = self.class.description_from_metadata_xml(metadata_string)
173
198
  begin
174
199
  metadata = JSON(description_text)
175
- _flattened_fields = metadata.key?('jpdfer_flattened_fields') ? metadata['jpdfer_flattened_fields'] : {}
200
+ flattened_fields = metadata.key?('jpdfer_flattened_fields') ? metadata['jpdfer_flattened_fields'] : {}
176
201
  rescue JSON::ParserError
177
- _flattened_fields = {}
202
+ flattened_fields = {}
178
203
  end
179
- h = {}
180
- _flattened_fields.each_pair do |name, value|
181
- h[name.to_sym] = value
204
+ flattened_fields.each_with_object({}) do |(name, value), fields|
205
+ fields[name.to_sym] = value
182
206
  end
183
- h
207
+ end
208
+
209
+ # Adds viewer preferences to the pdf.
210
+ # For all possible key value pairs see:
211
+ # http://api.itextpdf.com/itext/com/itextpdf/text/pdf/interfaces/PdfViewerPreferences.html#addViewerPreference(com.itextpdf.text.pdf.PdfName, com.itextpdf.text.pdf.PdfObject)
212
+ #
213
+ # keys and values can be passed in as lower or upper case symbols or strings
214
+ def add_viewer_preference(key, value)
215
+ converted_key = PdfName.const_get(key.upcase) rescue nil
216
+ converted_key ||= PdfBoolean.const_get(key.upcase)
217
+
218
+ converted_value = PdfName.const_get(value.upcase) rescue nil
219
+ converted_value ||= PdfBoolean.const_get(value.upcase)
220
+
221
+ @stamper.add_viewer_preference(converted_key, converted_value)
184
222
  end
185
223
 
186
224
  # true if the receiving Pdf instance was previously flattened with jpdfer
@@ -190,7 +228,7 @@ module Jpdfer
190
228
 
191
229
  # Returns the certification level of the pdf
192
230
  def certification_level
193
- case @stamper.reader.getCertificationLevel
231
+ case @reader.getCertificationLevel
194
232
  when PdfSignatureAppearance::CERTIFIED_FORM_FILLING
195
233
  level = :form_filling
196
234
  when PdfSignatureAppearance::CERTIFIED_FORM_FILLING_AND_ANNOTATIONS
@@ -241,6 +279,35 @@ module Jpdfer
241
279
  canvas.addImage(image, false)
242
280
  end
243
281
 
244
- end
282
+ # Replaces any javascript currently attached to the page with
283
+ # the contents of +script+
284
+ #
285
+ # Returns +script+
286
+ def javascript=(script)
287
+ @stamper.addJavaScript(script)
288
+ script
289
+ end
290
+
291
+ private
245
292
 
293
+ def init(data)
294
+ @data = data
295
+ @reader = PdfReader.new(data.to_java_bytes)
296
+ @output_buffer = StringIO.new
297
+ @stamper = create_stamper
298
+ end
299
+
300
+ def create_stamper
301
+ if @keystore
302
+ stamper = PdfStamper.createSignature(@reader, @output_buffer.to_outputstream, 0)
303
+ key, certificate_chain = @keystore.private_key, @keystore.certificate_chain
304
+ # TODO: Should not always be self-signed
305
+ signature_type = Pdf::PdfSignatureAppearance::SELF_SIGNED
306
+ stamper.getSignatureAppearance.setCrypto(key, certificate_chain, nil, signature_type)
307
+ else
308
+ stamper = PdfStamper.new(@reader, @output_buffer.to_outputstream)
309
+ end
310
+ stamper
311
+ end
312
+ end
246
313
  end
@@ -1,3 +1,3 @@
1
1
  module Jpdfer
2
- VERSION = "0.3.1"
2
+ VERSION = "0.4.0"
3
3
  end
@@ -2,7 +2,7 @@ require 'spec_helper'
2
2
 
3
3
  module Jpdfer
4
4
 
5
- describe "Pdf Acceptance" do
5
+ describe Pdf do
6
6
  before(:each) do
7
7
  @data_path = File.join(ROOT, 'spec', 'data')
8
8
  @pdf_path = File.join(@data_path, 'simple_form.pdf')
@@ -109,7 +109,7 @@ describe "Pdf Acceptance" do
109
109
  FileUtils.rm_f(@save_path)
110
110
  end
111
111
 
112
- it 'should instaniate a new pdf a pass it to the block and then save it' do
112
+ it 'should instaniate a new pdf and yield it to the block and then save it' do
113
113
  Pdf.open(@pdf_path, @save_path) do |pdf|
114
114
  pdf.set_fields(@filled_fields)
115
115
  end
@@ -128,6 +128,41 @@ describe "Pdf Acceptance" do
128
128
  end
129
129
  end
130
130
 
131
+ describe '.concatenate' do
132
+ before(:each) do
133
+ @pdf_1, @pdf_2 = Pdf.new(@pdf_path), Pdf.new(@pdf_path)
134
+ @save_path = File.join(@data_path, 'new_pdf.pdf')
135
+ end
136
+
137
+ after(:each) do
138
+ FileUtils.rm_f(@save_path)
139
+ end
140
+
141
+ it 'should return a new pdf with the pages of all the given pdfs' do
142
+ pdf = Pdf.concatenate([@pdf_1, @pdf_2])
143
+ pdf.number_of_pages.should == @pdf_1.number_of_pages + @pdf_2.number_of_pages
144
+ end
145
+
146
+ it 'should yield the pdf if given a block and then save it' do
147
+ Pdf.concatenate([@pdf_1, @pdf_2], @save_path) do |pdf|
148
+ pdf.number_of_pages.should == @pdf_1.number_of_pages + @pdf_2.number_of_pages
149
+ end
150
+
151
+ new_pdf = Pdf.new(@save_path)
152
+ new_pdf.number_of_pages.should == @pdf_1.number_of_pages + @pdf_2.number_of_pages
153
+ end
154
+ end
155
+
156
+ describe 'forwards any potential messages to the reader if it will respond' do
157
+ it 'should respond to number_of_pages' do
158
+ @pdf.number_of_pages.should == 1
159
+ end
160
+
161
+ it 'should not respond to foo_bar' do
162
+ lambda { @pdf.foo_bar }.should raise_error NoMethodError
163
+ end
164
+ end
165
+
131
166
  describe '#page_size' do
132
167
  it 'should return the page size as an array of floats' do
133
168
  @pdf.page_size.should == [612.0, 792.0]
@@ -274,30 +309,6 @@ describe "Pdf Acceptance" do
274
309
  new_pdf.should_not have_form
275
310
  end
276
311
  end
277
-
278
- describe 'with a saved PDF' do
279
- before(:each) do
280
- @pdf.save_as(@new_path)
281
- end
282
-
283
- describe 'saving again' do
284
- it "should raise Pdf::ReadOnlyError" do
285
- lambda { @pdf.save_as(@new_path) }.should raise_error(Pdf::ReadOnlyError, /Cannot save a previously saved pdf/)
286
- end
287
- end
288
-
289
- describe "#set_field" do
290
- it "should raise Pdf:ReadOnlyError" do
291
- lambda { @pdf.set_field(:important_field, 'I am important') }.should raise_error(Pdf::ReadOnlyError, /Previously saved pdfs are read-only/)
292
- end
293
- end
294
-
295
- describe "#set_fields" do
296
- it "should raise Pdf::ReadOnlyError" do
297
- lambda { @pdf.set_fields(@filled_fields) }.should raise_error(Pdf::ReadOnlyError, /Previously saved pdfs are read-only/)
298
- end
299
- end
300
- end
301
312
  end
302
313
 
303
314
  describe '#has_field?' do
metadata CHANGED
@@ -1,114 +1,107 @@
1
- --- !ruby/object:Gem::Specification
1
+ --- !ruby/object:Gem::Specification
2
2
  name: jpdfer
3
- version: !ruby/object:Gem::Version
4
- prerelease:
5
- version: 0.3.1
3
+ version: !ruby/object:Gem::Version
4
+ prerelease:
5
+ version: 0.4.0
6
6
  platform: java
7
- authors:
8
- - Scott Nielsen
9
- - David Brady
10
- autorequire:
7
+ authors:
8
+ - Scott Nielsen
9
+ - David Brady
10
+ autorequire:
11
11
  bindir: bin
12
12
  cert_chain: []
13
-
14
- date: 2012-09-21 00:00:00 Z
15
- dependencies:
16
- - !ruby/object:Gem::Dependency
17
- name: nokogiri
18
- prerelease: false
19
- requirement: &id001 !ruby/object:Gem::Requirement
20
- none: false
21
- requirements:
22
- - - ">="
23
- - !ruby/object:Gem::Version
24
- version: "0"
25
- type: :runtime
26
- version_requirements: *id001
27
- - !ruby/object:Gem::Dependency
28
- name: json-jruby
29
- prerelease: false
30
- requirement: &id002 !ruby/object:Gem::Requirement
31
- none: false
32
- requirements:
33
- - - ">="
34
- - !ruby/object:Gem::Version
35
- version: "0"
36
- type: :runtime
37
- version_requirements: *id002
38
- - !ruby/object:Gem::Dependency
39
- name: rspec
40
- prerelease: false
41
- requirement: &id003 !ruby/object:Gem::Requirement
42
- none: false
43
- requirements:
44
- - - ">="
45
- - !ruby/object:Gem::Version
46
- version: "0"
47
- type: :development
48
- version_requirements: *id003
13
+ date: 2012-09-26 00:00:00.000000000Z
14
+ dependencies:
15
+ - !ruby/object:Gem::Dependency
16
+ name: nokogiri
17
+ version_requirements: &2058 !ruby/object:Gem::Requirement
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: '0'
22
+ none: false
23
+ requirement: *2058
24
+ prerelease: false
25
+ type: :runtime
26
+ - !ruby/object:Gem::Dependency
27
+ name: json-jruby
28
+ version_requirements: &2076 !ruby/object:Gem::Requirement
29
+ requirements:
30
+ - - ! '>='
31
+ - !ruby/object:Gem::Version
32
+ version: '0'
33
+ none: false
34
+ requirement: *2076
35
+ prerelease: false
36
+ type: :runtime
37
+ - !ruby/object:Gem::Dependency
38
+ name: rspec
39
+ version_requirements: &2092 !ruby/object:Gem::Requirement
40
+ requirements:
41
+ - - ! '>='
42
+ - !ruby/object:Gem::Version
43
+ version: '0'
44
+ none: false
45
+ requirement: *2092
46
+ prerelease: false
47
+ type: :development
49
48
  description: Ruby-style wrapper in JRuby for reading and writing PDF forms
50
49
  email: scottnielsen5@gmail.com
51
50
  executables: []
52
-
53
51
  extensions: []
54
-
55
52
  extra_rdoc_files: []
56
-
57
- files:
58
- - README.rdoc
59
- - jars/bcmail-jdk16-146.jar
60
- - jars/bcprov-jdk16-146.jar
61
- - jars/bctsp-jdk16-146.jar
62
- - jars/itextpdf-5.1.1.jar
63
- - lib/jpdfer.rb
64
- - lib/jpdfer/key_store.rb
65
- - lib/jpdfer/page_sizes.rb
66
- - lib/jpdfer/pdf.rb
67
- - lib/jpdfer/version.rb
68
- - spec/spec_helper.rb
69
- - spec/acceptance/jpdfer/pdf_acceptance_spec.rb
70
- - spec/lib/jpdfer/pdf_spec.rb
71
- - spec/data/keystore.ks
72
- - spec/data/flattened.pdf
73
- - spec/data/simple_form.pdf
74
- - spec/data/simple_form_flattened.pdf
75
- - spec/data/simple_form_flattened_signed.pdf
76
- - spec/data/simple_form_signed_by_someone_else.pdf
53
+ files:
54
+ - README.rdoc
55
+ - jars/bcmail-jdk16-146.jar
56
+ - jars/bcprov-jdk16-146.jar
57
+ - jars/bctsp-jdk16-146.jar
58
+ - jars/itextpdf-5.1.1.jar
59
+ - lib/jpdfer.rb
60
+ - lib/jpdfer/key_store.rb
61
+ - lib/jpdfer/page_sizes.rb
62
+ - lib/jpdfer/pdf.rb
63
+ - lib/jpdfer/version.rb
64
+ - spec/pdf_spec.rb
65
+ - spec/spec_helper.rb
66
+ - spec/data/keystore.ks
67
+ - spec/data/flattened.pdf
68
+ - spec/data/simple_form.pdf
69
+ - spec/data/simple_form_flattened.pdf
70
+ - spec/data/simple_form_flattened_signed.pdf
71
+ - spec/data/simple_form_signed_by_someone_else.pdf
77
72
  homepage: http://github.com/scizo/jpdfer
78
73
  licenses: []
79
-
80
- post_install_message:
81
- rdoc_options:
82
- - --main
83
- - README.rdoc
84
- require_paths:
85
- - lib
86
- required_ruby_version: !ruby/object:Gem::Requirement
74
+ post_install_message:
75
+ rdoc_options:
76
+ - --main
77
+ - README.rdoc
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ requirements:
82
+ - - ! '>='
83
+ - !ruby/object:Gem::Version
84
+ version: '0'
87
85
  none: false
88
- requirements:
89
- - - ">="
90
- - !ruby/object:Gem::Version
91
- version: "0"
92
- required_rubygems_version: !ruby/object:Gem::Requirement
86
+ required_rubygems_version: !ruby/object:Gem::Requirement
87
+ requirements:
88
+ - - ! '>='
89
+ - !ruby/object:Gem::Version
90
+ version: '0'
93
91
  none: false
94
- requirements:
95
- - - ">="
96
- - !ruby/object:Gem::Version
97
- version: "0"
98
92
  requirements: []
99
-
100
- rubyforge_project:
93
+ rubyforge_project:
101
94
  rubygems_version: 1.8.15
102
- signing_key:
95
+ signing_key:
103
96
  specification_version: 3
104
97
  summary: Read and write PDF forms in JRuby
105
- test_files:
106
- - spec/spec_helper.rb
107
- - spec/acceptance/jpdfer/pdf_acceptance_spec.rb
108
- - spec/lib/jpdfer/pdf_spec.rb
109
- - spec/data/keystore.ks
110
- - spec/data/flattened.pdf
111
- - spec/data/simple_form.pdf
112
- - spec/data/simple_form_flattened.pdf
113
- - spec/data/simple_form_flattened_signed.pdf
114
- - spec/data/simple_form_signed_by_someone_else.pdf
98
+ test_files:
99
+ - spec/pdf_spec.rb
100
+ - spec/spec_helper.rb
101
+ - spec/data/keystore.ks
102
+ - spec/data/flattened.pdf
103
+ - spec/data/simple_form.pdf
104
+ - spec/data/simple_form_flattened.pdf
105
+ - spec/data/simple_form_flattened_signed.pdf
106
+ - spec/data/simple_form_signed_by_someone_else.pdf
107
+ ...
@@ -1,20 +0,0 @@
1
- require 'spec_helper'
2
-
3
-
4
- module Jpdfer
5
- # IMPORTANT: These are model/unit specs! Test in isolation as much as possible!
6
- describe Pdf do
7
- before(:each) do
8
- @data_path = File.join(ROOT, 'spec', 'data')
9
- @pdf_path = File.join(@data_path, 'simple_form.pdf')
10
- @pdf = Pdf.new(@pdf_path)
11
- end
12
-
13
- describe '.new' do
14
- it 'should create new pdf' do
15
- @pdf.should_not be_nil
16
- end
17
- end
18
- end
19
-
20
- end