jpdfer 0.3.1-java → 0.4.0-java

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/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