jpdfer 0.3.1-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/README.rdoc +14 -0
- data/jars/bcmail-jdk16-146.jar +0 -0
- data/jars/bcprov-jdk16-146.jar +0 -0
- data/jars/bctsp-jdk16-146.jar +0 -0
- data/jars/itextpdf-5.1.1.jar +0 -0
- data/lib/jpdfer/key_store.rb +23 -0
- data/lib/jpdfer/page_sizes.rb +62 -0
- data/lib/jpdfer/pdf.rb +246 -0
- data/lib/jpdfer/version.rb +3 -0
- data/lib/jpdfer.rb +17 -0
- data/spec/acceptance/jpdfer/pdf_acceptance_spec.rb +387 -0
- data/spec/data/flattened.pdf +0 -0
- data/spec/data/keystore.ks +0 -0
- data/spec/data/simple_form.pdf +0 -0
- data/spec/data/simple_form_flattened.pdf +0 -0
- data/spec/data/simple_form_flattened_signed.pdf +0 -0
- data/spec/data/simple_form_signed_by_someone_else.pdf +0 -0
- data/spec/lib/jpdfer/pdf_spec.rb +20 -0
- data/spec/spec_helper.rb +3 -0
- metadata +114 -0
data/README.rdoc
ADDED
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Jpdfer
|
2
|
+
|
3
|
+
class KeyStore
|
4
|
+
JavaFileInputStream = java.io.FileInputStream
|
5
|
+
JavaKeyStore = java.security.KeyStore
|
6
|
+
JavaString = java.lang.String
|
7
|
+
|
8
|
+
def initialize(keystore_path, _alias, password)
|
9
|
+
@alias, @password = _alias, password
|
10
|
+
@keystore = JavaKeyStore::getInstance(JavaKeyStore::getDefaultType())
|
11
|
+
@keystore.load(JavaFileInputStream.new(keystore_path), JavaString.new(@password).toCharArray)
|
12
|
+
end
|
13
|
+
|
14
|
+
def private_key
|
15
|
+
@keystore.getKey(@alias, java.lang.String.new(@password).toCharArray)
|
16
|
+
end
|
17
|
+
|
18
|
+
def certificate_chain
|
19
|
+
@keystore.getCertificateChain(@alias)
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
module Jpdfer
|
2
|
+
include_package "com.itextpdf.text"
|
3
|
+
|
4
|
+
def self.dimension_array(page_size)
|
5
|
+
[page_size.width, page_size.height]
|
6
|
+
end
|
7
|
+
|
8
|
+
PAGE_SIZES = {
|
9
|
+
dimension_array(PageSize::_11X17) => :'11x17',
|
10
|
+
dimension_array(PageSize::A0) => :a0,
|
11
|
+
dimension_array(PageSize::A1) => :a1,
|
12
|
+
dimension_array(PageSize::A10) => :a10,
|
13
|
+
dimension_array(PageSize::A2) => :a2,
|
14
|
+
dimension_array(PageSize::A3) => :a3,
|
15
|
+
dimension_array(PageSize::A4) => :a4,
|
16
|
+
dimension_array(PageSize::A5) => :a5,
|
17
|
+
dimension_array(PageSize::A6) => :a6,
|
18
|
+
dimension_array(PageSize::A7) => :a7,
|
19
|
+
dimension_array(PageSize::A8) => :a8,
|
20
|
+
dimension_array(PageSize::A9) => :a9,
|
21
|
+
dimension_array(PageSize::ARCH_A) => :arch_a,
|
22
|
+
dimension_array(PageSize::ARCH_B) => :arch_b,
|
23
|
+
dimension_array(PageSize::ARCH_C) => :arch_c,
|
24
|
+
dimension_array(PageSize::ARCH_D) => :arch_d,
|
25
|
+
dimension_array(PageSize::ARCH_E) => :arch_e,
|
26
|
+
dimension_array(PageSize::B0) => :b0,
|
27
|
+
dimension_array(PageSize::B1) => :b1,
|
28
|
+
dimension_array(PageSize::B10) => :b10,
|
29
|
+
dimension_array(PageSize::B2) => :b2,
|
30
|
+
dimension_array(PageSize::B3) => :b3,
|
31
|
+
dimension_array(PageSize::B4) => :b4,
|
32
|
+
dimension_array(PageSize::B5) => :b5,
|
33
|
+
dimension_array(PageSize::B6) => :b6,
|
34
|
+
dimension_array(PageSize::B7) => :b7,
|
35
|
+
dimension_array(PageSize::B8) => :b8,
|
36
|
+
dimension_array(PageSize::B9) => :b9,
|
37
|
+
dimension_array(PageSize::CROWN_OCTAVO) => :crown_octavo,
|
38
|
+
dimension_array(PageSize::CROWN_QUARTO) => :crown_quarto,
|
39
|
+
dimension_array(PageSize::DEMY_OCTAVO) => :demy_octavo,
|
40
|
+
dimension_array(PageSize::DEMY_QUARTO) => :demy_quarto,
|
41
|
+
dimension_array(PageSize::EXECUTIVE) => :executive,
|
42
|
+
dimension_array(PageSize::FLSA) => :flsa,
|
43
|
+
dimension_array(PageSize::FLSE) => :flse,
|
44
|
+
dimension_array(PageSize::HALFLETTER) => :halfletter,
|
45
|
+
dimension_array(PageSize::ID_1) => :id_1,
|
46
|
+
dimension_array(PageSize::ID_2) => :id_2,
|
47
|
+
dimension_array(PageSize::ID_3) => :id_3,
|
48
|
+
dimension_array(PageSize::LARGE_CROWN_OCTAVO) => :large_crown_octavo,
|
49
|
+
dimension_array(PageSize::LARGE_CROWN_QUARTO) => :large_crown_quarto,
|
50
|
+
dimension_array(PageSize::LEDGER) => :ledger,
|
51
|
+
dimension_array(PageSize::LEGAL) => :legal,
|
52
|
+
dimension_array(PageSize::LETTER) => :letter,
|
53
|
+
dimension_array(PageSize::NOTE) => :note,
|
54
|
+
dimension_array(PageSize::PENGUIN_LARGE_PAPERBACK) => :penguin_large_paperback,
|
55
|
+
dimension_array(PageSize::PENGUIN_SMALL_PAPERBACK) => :penguin_small_paperback,
|
56
|
+
dimension_array(PageSize::POSTCARD) => :postcard,
|
57
|
+
dimension_array(PageSize::ROYAL_OCTAVO) => :royal_octavo,
|
58
|
+
dimension_array(PageSize::ROYAL_QUARTO) => :royal_quarto,
|
59
|
+
dimension_array(PageSize::SMALL_PAPERBACK) => :small_paperback,
|
60
|
+
dimension_array(PageSize::TABLOID) => :tabloid
|
61
|
+
}
|
62
|
+
end
|
data/lib/jpdfer/pdf.rb
ADDED
@@ -0,0 +1,246 @@
|
|
1
|
+
require 'jpdfer/page_sizes'
|
2
|
+
# High-level/convenience wrapper class for a PDF document.
|
3
|
+
|
4
|
+
module Jpdfer
|
5
|
+
|
6
|
+
# PDF Document with a form that can be read, filled, and saved.
|
7
|
+
class Pdf
|
8
|
+
class NonexistentFieldError < Exception; end
|
9
|
+
class ReadOnlyError < Exception; end
|
10
|
+
include_class Java::com.itextpdf.text.Image
|
11
|
+
include_class Java::java.net.URL
|
12
|
+
include_package "com.itextpdf.text.pdf"
|
13
|
+
include_package "com.itextpdf.text.xml.xmp"
|
14
|
+
|
15
|
+
def self.create_flatten_fields_xml(fields)
|
16
|
+
schema = DublinCoreSchema.new
|
17
|
+
schema.addDescription(JSON({'jpdfer_flattened_fields' => fields}))
|
18
|
+
metaout = StringIO.new
|
19
|
+
xmpwriter = XmpWriter.new(metaout.to_outputstream)
|
20
|
+
xmpwriter.addRdfDescription(schema)
|
21
|
+
xmpwriter.close
|
22
|
+
metaout.string
|
23
|
+
end
|
24
|
+
|
25
|
+
def self.description_from_metadata_xml(metadata_string)
|
26
|
+
metadata_string.gsub!(/<\?.*?\?>/, '')
|
27
|
+
namespaces = {
|
28
|
+
"xmlns:x" => "adobe:ns:meta/",
|
29
|
+
"xmlns:rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#",
|
30
|
+
"xmlns:dc" => "http://purl.org/dc/elements/1.1/"
|
31
|
+
}
|
32
|
+
root_node = Nokogiri::XML.parse(metadata_string)
|
33
|
+
descriptions = root_node.xpath('.//dc:description//rdf:li/text()', namespaces)
|
34
|
+
descriptions.count > 0 ? descriptions.first.text : ""
|
35
|
+
end
|
36
|
+
|
37
|
+
def self.open(pdf_path, save_path, options={})
|
38
|
+
flatten = options.delete(:flatten)
|
39
|
+
pdf = self.new(pdf_path, options)
|
40
|
+
if block_given?
|
41
|
+
yield pdf
|
42
|
+
pdf.save_as(save_path, flatten)
|
43
|
+
else
|
44
|
+
pdf
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
# 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
|
55
|
+
end
|
56
|
+
|
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
|
69
|
+
end
|
70
|
+
|
71
|
+
# Writes PDF to +path+. If +flatten+ is true, also flattens the form
|
72
|
+
# so that the form is printed on the PDF document but the form is no
|
73
|
+
# longer editable.
|
74
|
+
#
|
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
|
+
# save_as returns *UNTESTED* if the PDF form is not valid
|
80
|
+
def save_as(path, flatten=false)
|
81
|
+
raise ReadOnlyError.new("Cannot save a previously saved pdf") if @saved
|
82
|
+
@saved = true
|
83
|
+
if flatten
|
84
|
+
metadata = self.class.create_flatten_fields_xml(fields)
|
85
|
+
@stamper.setXmpMetadata metadata.to_java_bytes
|
86
|
+
end
|
87
|
+
@stamper.setFormFlattening(flatten)
|
88
|
+
@stamper.close
|
89
|
+
File.open(path, 'wb') do |file|
|
90
|
+
file.write(@output_buffer.string)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# Returns the page size of the pdf as [width (Float), height (Float)]
|
95
|
+
def page_size
|
96
|
+
page_size = @stamper.reader.crop_box(1)
|
97
|
+
if @stamper.reader.page_rotation(1) % 180 == 0
|
98
|
+
[page_size.width, page_size.height]
|
99
|
+
else
|
100
|
+
[page_size.height, page_size.width]
|
101
|
+
end
|
102
|
+
end
|
103
|
+
|
104
|
+
# Returns the page type of the pdf or :unknown
|
105
|
+
# See Jpdfer::PAGES_SIZES
|
106
|
+
def page_type
|
107
|
+
PAGE_SIZES.fetch(page_size, :unknown)
|
108
|
+
end
|
109
|
+
|
110
|
+
# Returns fields defined in this PDF form and their values, if any.
|
111
|
+
# fields returns an empty hash if PDF document does not contain a form
|
112
|
+
def fields
|
113
|
+
form = @stamper.getAcroFields
|
114
|
+
h = {}
|
115
|
+
form.getFields.each_pair do |name, value|
|
116
|
+
h[name.to_sym] = form.getField(name)
|
117
|
+
end
|
118
|
+
h
|
119
|
+
end
|
120
|
+
|
121
|
+
# Returns value of named field.
|
122
|
+
#
|
123
|
+
# Raises Pdf::NonexistentFieldError if field does not exist.
|
124
|
+
# +name+:: Symbol name of field to retrieve
|
125
|
+
def get_field(name)
|
126
|
+
raise NonexistentFieldError.new("'#{name}' field does not exist in form") unless has_field?(name)
|
127
|
+
@stamper.getAcroFields.getField(name.to_s)
|
128
|
+
end
|
129
|
+
|
130
|
+
# Sets named field. set_field returns value set.
|
131
|
+
#
|
132
|
+
# Raises Pdf::NonexistentFieldError if field does not exist.
|
133
|
+
# +name+: Symbol naming the field to write
|
134
|
+
def set_field(name, value)
|
135
|
+
raise ReadOnlyError.new('Previously saved pdfs are read-only') if @saved
|
136
|
+
name = name.to_sym
|
137
|
+
raise NonexistentFieldError.new("'#{name}' field does not exist in form") unless has_field?(name)
|
138
|
+
@stamper.getAcroFields.setField(name.to_s, value.to_s)
|
139
|
+
value
|
140
|
+
end
|
141
|
+
|
142
|
+
# Sets many fields at once. Returns the hash of fields set (should
|
143
|
+
# always be equal to given set of fields).
|
144
|
+
#
|
145
|
+
# Raises Pdf::NonexistentFieldError if any field does not exist.
|
146
|
+
# +fields+:: A hash of :key => "value" pairs.
|
147
|
+
def set_fields(fields)
|
148
|
+
fields.each_pair do |name, value|
|
149
|
+
set_field(name, value)
|
150
|
+
end
|
151
|
+
fields
|
152
|
+
end
|
153
|
+
|
154
|
+
# true if field +name+ exists in form
|
155
|
+
#
|
156
|
+
# +name+:: Field name as Symbol (or String)
|
157
|
+
def has_field?(name)
|
158
|
+
fields.key?(name.to_sym)
|
159
|
+
end
|
160
|
+
|
161
|
+
# true if the receiving Pdf instance has a form
|
162
|
+
def has_form?
|
163
|
+
@stamper.getAcroFields.getFields.size > 0
|
164
|
+
end
|
165
|
+
|
166
|
+
# Returns field names and values that were written to a
|
167
|
+
# form in this pdf before flattening.
|
168
|
+
# Returns an empty hash if there are not any.
|
169
|
+
def flattened_fields
|
170
|
+
reader = @stamper.reader
|
171
|
+
metadata_string = String.from_java_bytes reader.getMetadata
|
172
|
+
description_text = self.class.description_from_metadata_xml(metadata_string)
|
173
|
+
begin
|
174
|
+
metadata = JSON(description_text)
|
175
|
+
_flattened_fields = metadata.key?('jpdfer_flattened_fields') ? metadata['jpdfer_flattened_fields'] : {}
|
176
|
+
rescue JSON::ParserError
|
177
|
+
_flattened_fields = {}
|
178
|
+
end
|
179
|
+
h = {}
|
180
|
+
_flattened_fields.each_pair do |name, value|
|
181
|
+
h[name.to_sym] = value
|
182
|
+
end
|
183
|
+
h
|
184
|
+
end
|
185
|
+
|
186
|
+
# true if the receiving Pdf instance was previously flattened with jpdfer
|
187
|
+
def has_flattened_fields?
|
188
|
+
flattened_fields.size > 0 ? true : false
|
189
|
+
end
|
190
|
+
|
191
|
+
# Returns the certification level of the pdf
|
192
|
+
def certification_level
|
193
|
+
case @stamper.reader.getCertificationLevel
|
194
|
+
when PdfSignatureAppearance::CERTIFIED_FORM_FILLING
|
195
|
+
level = :form_filling
|
196
|
+
when PdfSignatureAppearance::CERTIFIED_FORM_FILLING_AND_ANNOTATIONS
|
197
|
+
level = :form_filling_and_annotations
|
198
|
+
when PdfSignatureAppearance::CERTIFIED_NO_CHANGES_ALLOWED
|
199
|
+
level = :no_changes_allowed
|
200
|
+
when PdfSignatureAppearance::NOT_CERTIFIED
|
201
|
+
level = :not_certified
|
202
|
+
end
|
203
|
+
level
|
204
|
+
end
|
205
|
+
|
206
|
+
# Set the certification level on a pdf initialized with an optional keystore
|
207
|
+
#
|
208
|
+
# *level* must be one of :form_filling, :form_filling_and_annotations,
|
209
|
+
# :no_changes_allowed, :not_certified
|
210
|
+
def set_certification_level(level)
|
211
|
+
case level
|
212
|
+
when :form_filling
|
213
|
+
certification_level = PdfSignatureAppearance::CERTIFIED_FORM_FILLING
|
214
|
+
when :form_filling_and_annotations
|
215
|
+
certification_level = PdfSignatureAppearance::CERTIFIED_FORM_FILLING_AND_ANNOTATIONS
|
216
|
+
when :no_changes_allowed
|
217
|
+
certification_level = PdfSignatureAppearance::CERTIFIED_NO_CHANGES_ALLOWED
|
218
|
+
when :not_certified
|
219
|
+
level = PdfSignatureAppearance::NOT_CERTIFIED
|
220
|
+
end
|
221
|
+
@stamper.getSignatureAppearance.setCertificationLevel(certification_level)
|
222
|
+
end
|
223
|
+
|
224
|
+
# Sets the reason for the signature on the pdf
|
225
|
+
def set_signature_reason(reason)
|
226
|
+
@stamper.getSignatureAppearance.setReason(reason)
|
227
|
+
end
|
228
|
+
|
229
|
+
# Sets the location of the signature on the pdf
|
230
|
+
def set_signature_location(location)
|
231
|
+
@stamper.getSignatureAppearance.setLocation(location)
|
232
|
+
end
|
233
|
+
|
234
|
+
# Adds the image at +image_path+ to the given +page+, at coordinates +x+ and +y+
|
235
|
+
def add_image(image_path, page, x, y, scale=1.0)
|
236
|
+
raise ReadOnlyError.new('Previously saved pdfs are read-only') if @saved
|
237
|
+
canvas = @stamper.getOverContent(page)
|
238
|
+
image = Image.getInstance(image_path)
|
239
|
+
image.setAbsolutePosition(x, y)
|
240
|
+
image.scalePercent(scale * 100)
|
241
|
+
canvas.addImage(image, false)
|
242
|
+
end
|
243
|
+
|
244
|
+
end
|
245
|
+
|
246
|
+
end
|
data/lib/jpdfer.rb
ADDED
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'java'
|
2
|
+
require 'stringio'
|
3
|
+
require 'json'
|
4
|
+
require 'nokogiri'
|
5
|
+
|
6
|
+
module Jpdfer
|
7
|
+
ROOT = File.expand_path('..', File.dirname(__FILE__))
|
8
|
+
end
|
9
|
+
|
10
|
+
require File.expand_path('jars/itextpdf-5.1.1.jar', Jpdfer::ROOT)
|
11
|
+
require File.expand_path('jars/bcprov-jdk16-146.jar', Jpdfer::ROOT)
|
12
|
+
require File.expand_path('jars/bctsp-jdk16-146.jar', Jpdfer::ROOT)
|
13
|
+
require File.expand_path('jars/bcmail-jdk16-146.jar', Jpdfer::ROOT)
|
14
|
+
|
15
|
+
require 'jpdfer/pdf'
|
16
|
+
require 'jpdfer/key_store'
|
17
|
+
require 'jpdfer/version'
|
@@ -0,0 +1,387 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
module Jpdfer
|
4
|
+
|
5
|
+
describe "Pdf Acceptance" do
|
6
|
+
before(:each) do
|
7
|
+
@data_path = File.join(ROOT, 'spec', 'data')
|
8
|
+
@pdf_path = File.join(@data_path, 'simple_form.pdf')
|
9
|
+
@pdf = Pdf.new(@pdf_path)
|
10
|
+
@unfilled_fields = {
|
11
|
+
:important_field => '',
|
12
|
+
:unimportant_field => '',
|
13
|
+
:semiimportant_field => '',
|
14
|
+
:tuesday_field => '',
|
15
|
+
:must_not_be_left_blank_field => ''
|
16
|
+
}
|
17
|
+
@filled_fields = {
|
18
|
+
:important_field => "I am important",
|
19
|
+
:unimportant_field => 'I am unimportant',
|
20
|
+
:semiimportant_field => 'I am confused',
|
21
|
+
:tuesday_field => 'Is it Tuesday already?',
|
22
|
+
:must_not_be_left_blank_field => 'NOT BLANK'
|
23
|
+
}
|
24
|
+
end
|
25
|
+
|
26
|
+
describe '.new' do
|
27
|
+
it 'should create new pdf' do
|
28
|
+
@pdf.should_not be_nil
|
29
|
+
end
|
30
|
+
|
31
|
+
describe 'given missing file' do
|
32
|
+
it 'should raise Errno::ENOENT (File Not Found)' do
|
33
|
+
lambda { Pdf.new('derp.pdf') }.should raise_error(Errno::ENOENT)
|
34
|
+
end
|
35
|
+
end
|
36
|
+
|
37
|
+
describe 'given an optional keystore' do
|
38
|
+
describe 'when Pdf is configured' do
|
39
|
+
before(:each) do
|
40
|
+
@keystore = KeyStore.new(
|
41
|
+
File.join(@data_path, 'keystore.ks'),
|
42
|
+
'jpdfer',
|
43
|
+
'durrderp'
|
44
|
+
)
|
45
|
+
@pdf = Pdf.new(@pdf_path, :keystore => @keystore)
|
46
|
+
@signed_pdf_path = File.join(@data_path, 'new_signed.pdf')
|
47
|
+
end
|
48
|
+
|
49
|
+
after(:each) do
|
50
|
+
FileUtils.rm_f(@signed_pdf_path)
|
51
|
+
end
|
52
|
+
|
53
|
+
it 'should create a signed pdf if saved' do
|
54
|
+
@pdf.save_as(@signed_pdf_path)
|
55
|
+
File.open(@signed_pdf_path) do |file|
|
56
|
+
data = file.read
|
57
|
+
data['Scott Nielsen'].should == 'Scott Nielsen'
|
58
|
+
data['Saxton Horne'].should == 'Saxton Horne'
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
62
|
+
describe '#set_certification_level' do
|
63
|
+
it 'should have the given certification level when saved' do
|
64
|
+
@pdf.set_certification_level(:no_changes_allowed)
|
65
|
+
@pdf.save_as(@signed_pdf_path)
|
66
|
+
@pdf = Pdf.new(@signed_pdf_path)
|
67
|
+
@pdf.certification_level.should == :no_changes_allowed
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
# TODO: I would like to add this functionality but havn't researched the java
|
72
|
+
# KeyStore and encryption classes enough yet
|
73
|
+
#
|
74
|
+
# describe 'given a pdf signed with the private_key and certificate' do
|
75
|
+
# before(:each) do
|
76
|
+
# pdf_path = File.join(@data_path, 'simple_form_flattened_signed.pdf')
|
77
|
+
# @pdf = Pdf.new(pdf_path, :keystore => @keystore)
|
78
|
+
# end
|
79
|
+
|
80
|
+
# describe '#signed?' do
|
81
|
+
# it 'should be true' do
|
82
|
+
# @pdf.should be_signed
|
83
|
+
# end
|
84
|
+
# end
|
85
|
+
# end
|
86
|
+
|
87
|
+
# describe 'given a pdf not signed with the private_key and certificate' do
|
88
|
+
# before(:each) do
|
89
|
+
# pdf_path = File.join(@data_path, 'simple_form_signed_by_someone_else.pdf')
|
90
|
+
# @pdf = Pdf.new(pdf_path, :keystore => @keystore)
|
91
|
+
# end
|
92
|
+
|
93
|
+
# describe '#signed?' do
|
94
|
+
# it 'should be false' do
|
95
|
+
# @pdf.should_not be_signed
|
96
|
+
# end
|
97
|
+
# end
|
98
|
+
# end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe '.open' do
|
104
|
+
before(:each) do
|
105
|
+
@save_path = File.join(@data_path, 'new_pdf.pdf')
|
106
|
+
end
|
107
|
+
|
108
|
+
after(:each) do
|
109
|
+
FileUtils.rm_f(@save_path)
|
110
|
+
end
|
111
|
+
|
112
|
+
it 'should instaniate a new pdf a pass it to the block and then save it' do
|
113
|
+
Pdf.open(@pdf_path, @save_path) do |pdf|
|
114
|
+
pdf.set_fields(@filled_fields)
|
115
|
+
end
|
116
|
+
new_pdf = Pdf.new(@save_path)
|
117
|
+
new_pdf.fields.should == @filled_fields
|
118
|
+
end
|
119
|
+
|
120
|
+
describe 'given the flatten option' do
|
121
|
+
it 'should be saved with the flatten option' do
|
122
|
+
Pdf.open(@pdf_path, @save_path, :flatten => true) do |pdf|
|
123
|
+
pdf.set_fields(@filled_fields)
|
124
|
+
end
|
125
|
+
new_pdf = Pdf.new(@save_path)
|
126
|
+
new_pdf.flattened_fields.should == @filled_fields
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
130
|
+
|
131
|
+
describe '#page_size' do
|
132
|
+
it 'should return the page size as an array of floats' do
|
133
|
+
@pdf.page_size.should == [612.0, 792.0]
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
describe '#page_type' do
|
138
|
+
it 'should return the page type if it exists' do
|
139
|
+
@pdf.page_type.should == :letter
|
140
|
+
end
|
141
|
+
end
|
142
|
+
|
143
|
+
describe '#certification_level' do
|
144
|
+
it 'should return nil for an unsigned pdf' do
|
145
|
+
@pdf.certification_level.should == :not_certified
|
146
|
+
end
|
147
|
+
|
148
|
+
describe 'called on a signed pdf' do
|
149
|
+
before(:each) do
|
150
|
+
@pdf = Pdf.new(File.join(@data_path, 'simple_form_flattened_signed.pdf'))
|
151
|
+
end
|
152
|
+
|
153
|
+
it 'it should return the certification level' do
|
154
|
+
@pdf.certification_level.should == :no_changes_allowed
|
155
|
+
end
|
156
|
+
end
|
157
|
+
end
|
158
|
+
|
159
|
+
describe '#fields' do
|
160
|
+
it 'should return a hash of field name value pairs' do
|
161
|
+
@pdf.fields.should == @unfilled_fields
|
162
|
+
end
|
163
|
+
end
|
164
|
+
|
165
|
+
describe '#get_field' do
|
166
|
+
it 'should return the field value' do
|
167
|
+
@pdf.get_field(:important_field).should == ""
|
168
|
+
end
|
169
|
+
|
170
|
+
describe "with nonexistent field name" do
|
171
|
+
it "should raise Pdf::NonexistentFieldError" do
|
172
|
+
lambda { @pdf.get_field(:monkey) }.should raise_error(Pdf::NonexistentFieldError, /'monkey' field does not exist in form/)
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
describe '#set_field' do
|
178
|
+
it 'should fill the field with given name with given value' do
|
179
|
+
@pdf.set_field(:important_field, "I am important")
|
180
|
+
@pdf.get_field(:important_field).should == "I am important"
|
181
|
+
end
|
182
|
+
|
183
|
+
it 'should return the value written to the field' do
|
184
|
+
@pdf.set_field(:important_field, "I am important").should == 'I am important'
|
185
|
+
end
|
186
|
+
|
187
|
+
it 'should update fields' do
|
188
|
+
@pdf.set_field(:important_field, "I am important")
|
189
|
+
@pdf.fields.should == {
|
190
|
+
:important_field => 'I am important',
|
191
|
+
:unimportant_field => '',
|
192
|
+
:semiimportant_field => '',
|
193
|
+
:tuesday_field => '',
|
194
|
+
:must_not_be_left_blank_field => ''
|
195
|
+
}
|
196
|
+
end
|
197
|
+
|
198
|
+
describe "with existing field name" do
|
199
|
+
it "should not raise an error" do
|
200
|
+
lambda { @pdf.set_field(:important_field, 'I am important') }.should_not raise_error(Pdf::NonexistentFieldError)
|
201
|
+
end
|
202
|
+
end
|
203
|
+
|
204
|
+
describe "with nonexistent field name" do
|
205
|
+
it "should raise Pdf::NonexistentFieldError" do
|
206
|
+
lambda { @pdf.set_field(:monkey, 'Spider') }.should raise_error(Pdf::NonexistentFieldError, /'monkey' field does not exist in form/)
|
207
|
+
end
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
describe '#set_fields' do
|
212
|
+
it 'should fill the fields with given names with given values' do
|
213
|
+
@pdf.set_fields(@filled_fields)
|
214
|
+
@pdf.get_field(:important_field).should == "I am important"
|
215
|
+
@pdf.get_field(:unimportant_field).should == 'I am unimportant'
|
216
|
+
@pdf.get_field(:semiimportant_field).should == 'I am confused'
|
217
|
+
@pdf.get_field(:tuesday_field).should == 'Is it Tuesday already?'
|
218
|
+
@pdf.get_field(:must_not_be_left_blank_field).should == 'NOT BLANK'
|
219
|
+
end
|
220
|
+
|
221
|
+
it 'should update fields' do
|
222
|
+
@pdf.set_fields(@filled_fields)
|
223
|
+
@pdf.fields.should == @filled_fields
|
224
|
+
end
|
225
|
+
|
226
|
+
it 'should return the set fields' do
|
227
|
+
@pdf.set_fields(@filled_fields).should == @filled_fields
|
228
|
+
end
|
229
|
+
|
230
|
+
describe "with nonexistent field name" do
|
231
|
+
it "should raise Pdf::NonexistentFieldError" do
|
232
|
+
@filled_fields[:monkey] = "spider"
|
233
|
+
lambda { @pdf.set_fields(@filled_fields) }.should raise_error(Pdf::NonexistentFieldError, /'monkey' field does not exist in form/)
|
234
|
+
end
|
235
|
+
end
|
236
|
+
end
|
237
|
+
|
238
|
+
describe '#save_as' do
|
239
|
+
before(:each) do
|
240
|
+
@new_path = File.join(@data_path, 'simple_form_new.pdf')
|
241
|
+
FileUtils.rm_f(@new_path)
|
242
|
+
end
|
243
|
+
|
244
|
+
after(:each) do
|
245
|
+
FileUtils.rm_f(@new_path)
|
246
|
+
end
|
247
|
+
|
248
|
+
it 'should write the pdf to a new path' do
|
249
|
+
@pdf.save_as(@new_path)
|
250
|
+
|
251
|
+
new_pdf = Pdf.new(@new_path)
|
252
|
+
new_pdf.fields.should == {
|
253
|
+
:important_field => '',
|
254
|
+
:unimportant_field => '',
|
255
|
+
:semiimportant_field => '',
|
256
|
+
:tuesday_field => '',
|
257
|
+
:must_not_be_left_blank_field => ''
|
258
|
+
}
|
259
|
+
end
|
260
|
+
|
261
|
+
it 'should save updated fields to the new file' do
|
262
|
+
@pdf.set_field(:important_field, "I am important")
|
263
|
+
@pdf.save_as(@new_path)
|
264
|
+
|
265
|
+
new_pdf = Pdf.new(@new_path)
|
266
|
+
new_pdf.get_field(:important_field).should == "I am important"
|
267
|
+
end
|
268
|
+
|
269
|
+
describe 'given flatten=true' do
|
270
|
+
it 'should save the pdf without a form' do
|
271
|
+
@pdf.save_as(@new_path, true)
|
272
|
+
|
273
|
+
new_pdf = Pdf.new(@new_path)
|
274
|
+
new_pdf.should_not have_form
|
275
|
+
end
|
276
|
+
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
|
+
end
|
302
|
+
|
303
|
+
describe '#has_field?' do
|
304
|
+
describe "with field name as symbol" do
|
305
|
+
it 'should return true if the field exists' do
|
306
|
+
@pdf.has_field?(:important_field).should be(true)
|
307
|
+
end
|
308
|
+
|
309
|
+
it 'should return false if the field does not' do
|
310
|
+
@pdf.has_field?(:monkey).should be(false)
|
311
|
+
end
|
312
|
+
end
|
313
|
+
|
314
|
+
describe "with field name as string" do
|
315
|
+
it 'should return true if the field exists' do
|
316
|
+
@pdf.has_field?("important_field").should be(true)
|
317
|
+
end
|
318
|
+
|
319
|
+
it 'should return false if the field does not' do
|
320
|
+
@pdf.has_field?("monkey").should be(false)
|
321
|
+
end
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
describe '#has_form?' do
|
326
|
+
describe 'given a pdf with a form' do
|
327
|
+
it 'should return true' do
|
328
|
+
@pdf.should have_form
|
329
|
+
end
|
330
|
+
end
|
331
|
+
|
332
|
+
describe 'given a pdf without a form' do
|
333
|
+
it 'should return false' do
|
334
|
+
pdf = Pdf.new(File.join(@data_path, 'simple_form_flattened.pdf'))
|
335
|
+
pdf.should_not have_form
|
336
|
+
end
|
337
|
+
end
|
338
|
+
end
|
339
|
+
|
340
|
+
describe 'given a pdf that we have flattened' do
|
341
|
+
before(:each) do
|
342
|
+
@new_pdf_path = File.join(@data_path, 'we_flattened.pdf')
|
343
|
+
@pdf.set_fields(@filled_fields)
|
344
|
+
@pdf.save_as(@new_pdf_path, true)
|
345
|
+
@pdf = Pdf.new(@new_pdf_path)
|
346
|
+
end
|
347
|
+
|
348
|
+
after(:each) do
|
349
|
+
FileUtils.rm_f(@new_pdf_path)
|
350
|
+
end
|
351
|
+
|
352
|
+
describe '#flattened_fields' do
|
353
|
+
it 'returns a hash of field name value pairs of previous form fields' do
|
354
|
+
@pdf.flattened_fields.should == @filled_fields
|
355
|
+
end
|
356
|
+
end
|
357
|
+
|
358
|
+
describe '#has_flattened_fields?' do
|
359
|
+
it 'should return true' do
|
360
|
+
@pdf.should have_flattened_fields
|
361
|
+
end
|
362
|
+
end
|
363
|
+
end
|
364
|
+
|
365
|
+
describe 'given a pdf that is not flattened, or we did not flatten' do
|
366
|
+
before(:each) do
|
367
|
+
@pdf = Pdf.new(File.join(@data_path, 'simple_form_flattened.pdf'))
|
368
|
+
end
|
369
|
+
|
370
|
+
describe '#flattened_fields' do
|
371
|
+
it 'should return an empty hash' do
|
372
|
+
@pdf.flattened_fields.should == {}
|
373
|
+
end
|
374
|
+
end
|
375
|
+
|
376
|
+
describe '#has_flattened_fields' do
|
377
|
+
it 'should be false' do
|
378
|
+
@pdf.should_not have_flattened_fields
|
379
|
+
end
|
380
|
+
end
|
381
|
+
end
|
382
|
+
|
383
|
+
# set_field returns some error if the form field is incorrect (e.g. setting a checkbox with something silly like 'monkey' or 'true' instead of 'Yes'
|
384
|
+
# save_as returns *UNTESTED* if the PDF form is not valid
|
385
|
+
end
|
386
|
+
|
387
|
+
end
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
Binary file
|
@@ -0,0 +1,20 @@
|
|
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
|
data/spec/spec_helper.rb
ADDED
metadata
ADDED
@@ -0,0 +1,114 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: jpdfer
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease:
|
5
|
+
version: 0.3.1
|
6
|
+
platform: java
|
7
|
+
authors:
|
8
|
+
- Scott Nielsen
|
9
|
+
- David Brady
|
10
|
+
autorequire:
|
11
|
+
bindir: bin
|
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
|
49
|
+
description: Ruby-style wrapper in JRuby for reading and writing PDF forms
|
50
|
+
email: scottnielsen5@gmail.com
|
51
|
+
executables: []
|
52
|
+
|
53
|
+
extensions: []
|
54
|
+
|
55
|
+
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
|
77
|
+
homepage: http://github.com/scizo/jpdfer
|
78
|
+
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
|
87
|
+
none: false
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: "0"
|
92
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
93
|
+
none: false
|
94
|
+
requirements:
|
95
|
+
- - ">="
|
96
|
+
- !ruby/object:Gem::Version
|
97
|
+
version: "0"
|
98
|
+
requirements: []
|
99
|
+
|
100
|
+
rubyforge_project:
|
101
|
+
rubygems_version: 1.8.15
|
102
|
+
signing_key:
|
103
|
+
specification_version: 3
|
104
|
+
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
|