Class: Jpdfer::Pdf
- Inherits:
-
Object
- Object
- Jpdfer::Pdf
- Defined in:
- lib/jpdfer/pdf.rb
Overview
PDF Document with a form that can be read, filled, and saved.
Defined Under Namespace
Classes: NonexistentFieldError, ReadOnlyError
Class Method Summary collapse
-
.concatenate(pdfs, save_path = nil, options = {}) ⇒ Object
A convenience method which concatenates the pages of several pdfs into one pdf.
- .create_flatten_fields_xml(fields) ⇒ Object
- .description_from_metadata_xml(metadata_string) ⇒ Object
-
.open(pdf_path, save_path = nil, options = {}) ⇒ Object
A convenience method which initializes a new pdf.
Instance Method Summary collapse
-
#add_image(image_path, page, x, y, scale = 1.0) ⇒ Object
Adds the image at
image_path
to the givenpage
, at coordinatesx
andy
. -
#add_viewer_preference(key, value) ⇒ Object
Adds viewer preferences to the pdf.
-
#add_watermark(text, options = {}) ⇒ Object
Add watermark text to all pages at coordinates
x
andy
. -
#certification_level ⇒ Object
Returns the certification level of the pdf.
-
#fields ⇒ Object
Returns fields defined in this PDF form and their values, if any.
-
#flattened_fields ⇒ Object
Returns field names and values that were written to a form in this pdf before flattening.
-
#get_field(name) ⇒ Object
Returns value of named field.
-
#has_field?(name) ⇒ Boolean
true if field
name
exists in form. -
#has_flattened_fields? ⇒ Boolean
true if the receiving Pdf instance was previously flattened with jpdfer.
-
#has_form? ⇒ Boolean
true if the receiving Pdf instance has a form.
-
#initialize(file_or_path, options = {}) ⇒ Pdf
constructor
Currently the only option is :keystore.
-
#inspect ⇒ Object
Returns a string representation of the Pdf object.
-
#javascript=(script) ⇒ Object
Replaces any javascript currently attached to the page with the contents of
script
. -
#method_missing(method, *args) ⇒ Object
Instances of Pdf forward any possible unknown method calls to the underlying iText PdfReader instance.
-
#page_size ⇒ Object
Returns the page size of the pdf as [width (Float), height (Float)].
-
#page_type ⇒ Object
Returns the page type of the pdf or :unknown See Jpdfer::PAGES_SIZES.
-
#reader ⇒ Object
Returns an independent instance of the underlying iText PdfReader.
-
#save_as(path, flatten = false) ⇒ Object
Writes PDF to
path
. -
#set_certification_level(level) ⇒ Object
Set the certification level on a pdf initialized with an optional keystore.
-
#set_field(name, value) ⇒ Object
Sets named field.
-
#set_fields(fields) ⇒ Object
Sets many fields at once.
-
#set_signature_location(location) ⇒ Object
Sets the location of the signature on the pdf.
-
#set_signature_reason(reason) ⇒ Object
Sets the reason for the signature on the pdf.
Constructor Details
#initialize(file_or_path, options = {}) ⇒ Pdf
Currently the only option is :keystore
91 92 93 94 95 96 97 98 |
# File 'lib/jpdfer/pdf.rb', line 91 def initialize(file_or_path, = {}) data = file_or_path.read if file_or_path.respond_to?(:read) data ||= File.read file_or_path @keystore = [:keystore] init(data) end |
Dynamic Method Handling
This class handles dynamic methods through the method_missing method
#method_missing(method, *args) ⇒ Object
Instances of Pdf forward any possible unknown method calls to the underlying iText PdfReader instance
102 103 104 105 |
# File 'lib/jpdfer/pdf.rb', line 102 def method_missing(method, *args) return @reader.send(method, *args) if @reader.respond_to? method super end |
Class Method Details
.concatenate(pdfs, save_path = nil, options = {}) ⇒ Object
A convenience method which concatenates the pages of several pdfs into one pdf. If a block is given, the new pdf is yielded and saved to save_path
after the block has been called.
The available options are :keystore and :flatten.
Returns the created pdf. If no block is given, save_as must be called to save the pdf.
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 |
# File 'lib/jpdfer/pdf.rb', line 48 def self.concatenate(pdfs, save_path=nil, ={}) output_buffer = StringIO.new flatten = .delete(:flatten) concatenator = PdfCopyFields.new output_buffer.to_outputstream pdfs.each do |pdf, page_range| if page_range PageRangeUtilities::normalize_page_range(page_range).each do |pages| # We need to help jruby convert Fixnum to java.lang.Integer. It defaults to java.lang.Long pages = pages.map {|page| Java::JavaLang::Integer.new page} concatenator.addDocument pdf.reader, pages end else concatenator.addDocument pdf.reader end end concatenator.close pdf = new(StringIO.new(output_buffer.string), ) if block_given? yield pdf pdf.save_as(save_path, flatten) end pdf end |
.create_flatten_fields_xml(fields) ⇒ Object
20 21 22 23 24 25 26 27 28 |
# File 'lib/jpdfer/pdf.rb', line 20 def self.create_flatten_fields_xml(fields) schema = DublinCoreSchema.new schema.addDescription(JSON({'jpdfer_flattened_fields' => fields})) = StringIO.new xmpwriter = XmpWriter.new(.to_outputstream) xmpwriter.addRdfDescription(schema) xmpwriter.close .string end |
.description_from_metadata_xml(metadata_string) ⇒ Object
30 31 32 33 34 35 36 37 38 39 40 |
# File 'lib/jpdfer/pdf.rb', line 30 def self.() .gsub!(/<\?.*?\?>/, '') namespaces = { "xmlns:x" => "adobe:ns:meta/", "xmlns:rdf" => "http://www.w3.org/1999/02/22-rdf-syntax-ns#", "xmlns:dc" => "http://purl.org/dc/elements/1.1/" } root_node = Nokogiri::XML.parse() descriptions = root_node.xpath('.//dc:description//rdf:li/text()', namespaces) descriptions.count > 0 ? descriptions.first.text : "" end |
.open(pdf_path, save_path = nil, options = {}) ⇒ Object
A convenience method which initializes a new pdf. If a block is given, the new pdf is yielded and saved to save_path
after the block has been called.
The options accept :flatten and :keystore.
Returns the created pdf. If no block is given, save_as must be called to save the pdf.
80 81 82 83 84 85 86 87 88 |
# File 'lib/jpdfer/pdf.rb', line 80 def self.open(pdf_path, save_path=nil, ={}) flatten = .delete(:flatten) pdf = new(pdf_path, ) if block_given? yield pdf pdf.save_as(save_path, flatten) end pdf end |
Instance Method Details
#add_image(image_path, page, x, y, scale = 1.0) ⇒ Object
Adds the image at image_path
to the given page
, at coordinates x
and y
286 287 288 289 290 291 292 293 |
# File 'lib/jpdfer/pdf.rb', line 286 def add_image(image_path, page, x, y, scale=1.0) raise ReadOnlyError.new('Previously saved pdfs are read-only') if @saved canvas = @stamper.getOverContent(page) image = Image.getInstance(image_path) image.setAbsolutePosition(x, y) image.scalePercent(scale * 100) canvas.addImage(image, false) end |
#add_viewer_preference(key, value) ⇒ Object
Adds viewer preferences to the pdf. For all possible key value pairs see: api.itextpdf.com/itext/com/itextpdf/text/pdf/interfaces/PdfViewerPreferences.html#addViewerPreference(com.itextpdf.text.pdf.PdfName, com.itextpdf.text.pdf.PdfObject)
keys and values can be passed in as lower or upper case symbols or strings
227 228 229 230 231 232 233 234 235 |
# File 'lib/jpdfer/pdf.rb', line 227 def add_viewer_preference(key, value) converted_key = PdfName.const_get(key.upcase) rescue nil converted_key ||= PdfBoolean.const_get(key.upcase) converted_value = PdfName.const_get(value.upcase) rescue nil converted_value ||= PdfBoolean.const_get(value.upcase) @stamper.add_viewer_preference(converted_key, converted_value) end |
#add_watermark(text, options = {}) ⇒ Object
Add watermark text to all pages at coordinates x
and y
options:
:x The placement of the watermark on the x-axis
Default: The center of the pdf
:y The placement of the watermark on the y-axis
Default: The center of the pdf
:font should be an instance of com.itextpdf.text.Font to be used for the watermark.
Default: Helvetica Bold 132pt 0.9 Gray
:rotation is an angle given in degrees that will rotate the watermark.
Default: 45
:alignment one of the com.itextpdf.text.Element alignment values
Default: ALIGN_CENTER
314 315 316 317 318 319 320 321 322 323 324 325 326 327 |
# File 'lib/jpdfer/pdf.rb', line 314 def add_watermark(text, ={}) raise ReadOnlyError.new('Previously saved pdfs are read-only') if @saved x = [:x] || @reader.crop_box(1).width / 2 y = [:y] || @reader.crop_box(1).height / 2 alignment = [:alignment] || Element::ALIGN_CENTER phrase = Phrase.new(text, [:font] || default_watermark_font) rotation = [:rotation] || 45 1.upto(@reader.getNumberOfPages).each do |page| canvas = @stamper.getUnderContent(page) ColumnText.showTextAligned(canvas, alignment, phrase, x, y, rotation) end end |
#certification_level ⇒ Object
Returns the certification level of the pdf
243 244 245 246 247 248 249 250 251 252 253 254 255 |
# File 'lib/jpdfer/pdf.rb', line 243 def certification_level case @reader.getCertificationLevel when PdfSignatureAppearance::CERTIFIED_FORM_FILLING level = :form_filling when PdfSignatureAppearance::CERTIFIED_FORM_FILLING_AND_ANNOTATIONS level = :form_filling_and_annotations when PdfSignatureAppearance::CERTIFIED_NO_CHANGES_ALLOWED level = :no_changes_allowed when PdfSignatureAppearance::NOT_CERTIFIED level = :not_certified end level end |
#fields ⇒ Object
Returns fields defined in this PDF form and their values, if any. fields returns an empty hash if PDF document does not contain a form
156 157 158 159 160 161 |
# File 'lib/jpdfer/pdf.rb', line 156 def fields form = @stamper.getAcroFields form.getFields.each_with_object({}) do |(name, value), fields| fields[name.to_sym] = form.getField(name) end end |
#flattened_fields ⇒ Object
Returns field names and values that were written to a form in this pdf before flattening. Returns an empty hash if there are not any.
208 209 210 211 212 213 214 215 216 217 218 219 220 |
# File 'lib/jpdfer/pdf.rb', line 208 def flattened_fields = String.from_java_bytes @reader.getMetadata description_text = self.class.() begin = JSON(description_text) flattened_fields = .key?('jpdfer_flattened_fields') ? ['jpdfer_flattened_fields'] : {} rescue JSON::ParserError flattened_fields = {} end flattened_fields.each_with_object({}) do |(name, value), fields| fields[name.to_sym] = value end end |
#get_field(name) ⇒ Object
Returns value of named field.
Raises Pdf::NonexistentFieldError if field does not exist.
name
-
Symbol name of field to retrieve
167 168 169 170 |
# File 'lib/jpdfer/pdf.rb', line 167 def get_field(name) raise NonexistentFieldError.new("'#{name}' field does not exist in form") unless has_field?(name) @stamper.getAcroFields.getField(name.to_s) end |
#has_field?(name) ⇒ Boolean
true if field name
exists in form
name
-
Field name as Symbol (or String)
196 197 198 |
# File 'lib/jpdfer/pdf.rb', line 196 def has_field?(name) fields.key?(name.to_sym) end |
#has_flattened_fields? ⇒ Boolean
true if the receiving Pdf instance was previously flattened with jpdfer
238 239 240 |
# File 'lib/jpdfer/pdf.rb', line 238 def has_flattened_fields? flattened_fields.size > 0 ? true : false end |
#has_form? ⇒ Boolean
true if the receiving Pdf instance has a form
201 202 203 |
# File 'lib/jpdfer/pdf.rb', line 201 def has_form? @stamper.getAcroFields.getFields.size > 0 end |
#inspect ⇒ Object
Returns a string representation of the Pdf object
113 114 115 |
# File 'lib/jpdfer/pdf.rb', line 113 def inspect "<Jpdfer::Pdf @reader=#{@reader}, @stamper=#{@stamper}>" end |
#javascript=(script) ⇒ Object
Replaces any javascript currently attached to the page with the contents of script
Returns script
333 334 335 336 |
# File 'lib/jpdfer/pdf.rb', line 333 def javascript=(script) @stamper.addJavaScript(script) script end |
#page_size ⇒ Object
Returns the page size of the pdf as [width (Float), height (Float)]
139 140 141 142 143 144 145 146 |
# File 'lib/jpdfer/pdf.rb', line 139 def page_size page_size = @reader.crop_box(1) if @reader.page_rotation(1) % 180 == 0 [page_size.width, page_size.height] else [page_size.height, page_size.width] end end |
#page_type ⇒ Object
Returns the page type of the pdf or :unknown See Jpdfer::PAGES_SIZES
150 151 152 |
# File 'lib/jpdfer/pdf.rb', line 150 def page_type PAGE_SIZES.fetch(page_size, :unknown) end |
#reader ⇒ Object
Returns an independent instance of the underlying iText PdfReader.
108 109 110 |
# File 'lib/jpdfer/pdf.rb', line 108 def reader PdfReader.new @data.to_java_bytes end |
#save_as(path, flatten = false) ⇒ Object
Writes PDF to path
. If flatten
is true, also flattens the form so that the form is printed on the PDF document but the form is no longer editable.
save_as returns UNTESTED if the PDF form is not valid
122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 |
# File 'lib/jpdfer/pdf.rb', line 122 def save_as(path, flatten=false) if flatten = self.class.create_flatten_fields_xml(fields) @stamper.setXmpMetadata .to_java_bytes end @stamper.setFormFlattening(flatten) @stamper.close File.open(path, 'wb') do |file| file.write(@output_buffer.string) end init(@output_buffer.string) end |
#set_certification_level(level) ⇒ Object
Set the certification level on a pdf initialized with an optional keystore
level must be one of :form_filling, :form_filling_and_annotations, :no_changes_allowed, :not_certified
261 262 263 264 265 266 267 268 269 270 271 272 273 |
# File 'lib/jpdfer/pdf.rb', line 261 def set_certification_level(level) case level when :form_filling certification_level = PdfSignatureAppearance::CERTIFIED_FORM_FILLING when :form_filling_and_annotations certification_level = PdfSignatureAppearance::CERTIFIED_FORM_FILLING_AND_ANNOTATIONS when :no_changes_allowed certification_level = PdfSignatureAppearance::CERTIFIED_NO_CHANGES_ALLOWED when :not_certified level = PdfSignatureAppearance::NOT_CERTIFIED end @stamper.getSignatureAppearance.setCertificationLevel(certification_level) end |
#set_field(name, value) ⇒ Object
Sets named field. set_field returns value set.
name
: Symbol naming the field to write
175 176 177 178 179 180 |
# File 'lib/jpdfer/pdf.rb', line 175 def set_field(name, value) name = name.to_sym raise NonexistentFieldError.new("'#{name}' field does not exist in form") unless has_field?(name) @stamper.getAcroFields.setField(name.to_s, value.to_s) value end |
#set_fields(fields) ⇒ Object
Sets many fields at once. Returns the hash of fields set (should always be equal to given set of fields).
fields
-
A hash of :key => “value” pairs.
186 187 188 189 190 191 |
# File 'lib/jpdfer/pdf.rb', line 186 def set_fields(fields) fields.each_pair do |name, value| set_field(name, value) end fields end |
#set_signature_location(location) ⇒ Object
Sets the location of the signature on the pdf
281 282 283 |
# File 'lib/jpdfer/pdf.rb', line 281 def set_signature_location(location) @stamper.getSignatureAppearance.setLocation(location) end |
#set_signature_reason(reason) ⇒ Object
Sets the reason for the signature on the pdf
276 277 278 |
# File 'lib/jpdfer/pdf.rb', line 276 def set_signature_reason(reason) @stamper.getSignatureAppearance.setReason(reason) end |