Class: PDF::Toolkit

Inherits:
Object
  • Object
show all
Extended by:
Forwardable, ClassMethods, Native
Includes:
Enumerable, Coercions
Defined in:
lib/pdf/toolkit.rb,
lib/pdf/toolkit/native.rb,
lib/pdf/toolkit/coercions.rb,
lib/pdf/toolkit/class_methods.rb

Overview

PDF::Toolkit can be used as a simple class, or derived from and tweaked. The following two examples have identical results.

my_pdf = PDF::Toolkit.open("somefile.pdf")
my_pdf.updated_at = Time.now # ModDate
my_pdf["SomeAttribute"] = "Some value"
my_pdf.save!

class MyDocument < PDF::Toolkit
  info_accessor :some_attribute
  def before_save
    self.updated_at = Time.now
  end
end
my_pdf = MyDocument.open("somefile.pdf")
my_pdf.some_attribute = "Some value"
my_pdf.save!

Note the use of a before_save callback in the second example. This is the only supported callback unless you use the experimental #loot_active_record class method.

Requirements

PDF::Toolkit requires pdftk, which is available from www.accesspdf.com/pdftk. For full functionality, also install xpdf from www.foolabs.com/xpdf.

Limitations

Timestamps are written in UTF-16 by pdftk, which is not appropriately handled by pdfinfo.

pdftk requires the owner password, even for simply querying the document.

Defined Under Namespace

Modules: ClassMethods, Coercions, Native Classes: Error, ExecutionError, FileNotSaved

Constant Summary collapse

VERSION =
"1.1.0"

Instance Attribute Summary collapse

Attributes included from ClassMethods

#default_input_password, #default_owner_password, #default_permissions, #default_user_password

Class Method Summary collapse

Instance Method Summary collapse

Methods included from Native

pdftk, pdftotext

Methods included from ClassMethods

camelize_key, info_accessor, info_accessors

Methods included from Coercions

#cast_field, #format_field, #format_time, #parse_time

Constructor Details

#initialize(filename, input_password = nil) ⇒ Toolkit

Like open, only the attributes are lazily loaded. Under most circumstances, open is preferred.



88
89
90
91
92
93
94
95
96
97
98
99
# File 'lib/pdf/toolkit.rb', line 88

def initialize(filename, input_password = nil)
  coercer = [:to_path, :to_str, :path].find{|meth| filename.respond_to? meth}
  @filename = coercer ? filename.send(coercer) : filename

  @input_password = input_password || default_input_password
  @owner_password = default_owner_password
  @user_password  = default_user_password
  @permissions    = default_permissions || []
  @new_info       = {}

  run_callbacks_for(:after_initialize)
end

Instance Attribute Details

#owner_password=(value) ⇒ Object (writeonly)

Sets the attribute owner_password

Parameters:

  • value

    the value to set the attribute owner_password to.



107
108
109
# File 'lib/pdf/toolkit.rb', line 107

def owner_password=(value)
  @owner_password = value
end

#pdf_idsObject (readonly)

Returns the value of attribute pdf_ids.



106
107
108
# File 'lib/pdf/toolkit.rb', line 106

def pdf_ids
  @pdf_ids
end

#permissionsObject (readonly)

Returns the value of attribute permissions.



106
107
108
# File 'lib/pdf/toolkit.rb', line 106

def permissions
  @permissions
end

#user_password=(value) ⇒ Object (writeonly)

Sets the attribute user_password

Parameters:

  • value

    the value to set the attribute user_password to.



107
108
109
# File 'lib/pdf/toolkit.rb', line 107

def user_password=(value)
  @user_password = value
end

Class Method Details

.open(filename, input_password = nil) ⇒ Object

Create a new object associated with filename and read in the associated metadata.

my_pdf = PDF::Toolkit.open("document.pdf")


80
81
82
83
84
# File 'lib/pdf/toolkit.rb', line 80

def self.open(filename,input_password = nil)
  object = new(filename,input_password)
  object.reload
  block_given? ? yield(object) : object
end

Instance Method Details

#[](key) ⇒ Object

Read a metadata attribute.

author = my_pdf["Author"]

See info_accessor for an alternate syntax.



200
201
202
203
204
205
# File 'lib/pdf/toolkit.rb', line 200

def [](key)
  key = lookup_key(key)
  return @new_info[key.to_s] if @new_info.has_key?(key.to_s)
  ensure_loaded
  @info[key.to_s]
end

#[]=(key, value) ⇒ Object

Write a metadata attribute.

my_pdf["Author"] = author

See info_accessor for an alternate syntax.



212
213
214
215
# File 'lib/pdf/toolkit.rb', line 212

def []=(key,value)
  key = lookup_key(key)
  @new_info[key.to_s] = value
end

#delete(key) ⇒ Object

Remove the metadata attribute from the file.



231
232
233
234
235
236
237
238
# File 'lib/pdf/toolkit.rb', line 231

def delete(key)
  key = lookup_key(key)
  if @info.has_key?(key) || !@pages
    @new_info[key] = nil
  else
    @new_info.delete(key)
  end
end

#delete_if(&block) ⇒ Object

Remove metadata if the given block returns false. The following would remove all timestamps.

my_pdf.delete_if {|key,value| value.kind_of?(Time)}


257
258
259
260
# File 'lib/pdf/toolkit.rb', line 257

def delete_if(&block)
  reject!(&block)
  self
end

#has_key?(value) ⇒ Boolean Also known as: key?

True if the file has the given metadata attribute.

Returns:

  • (Boolean)


223
224
225
226
227
# File 'lib/pdf/toolkit.rb', line 223

def has_key?(value)
  ensure_loaded
  value = lookup_key(value)
  (@info.has_key?(value) || @new_info.has_key?(value)) && !!(self[value])
end

#merge!(hash) ⇒ Object

Add the specified attributes to the file. If symbols are given as keys, they are camelized.

my_pdf.merge!(“Author” => “Dave Thomas”, :title => “Programming Ruby”)



266
267
268
269
270
271
# File 'lib/pdf/toolkit.rb', line 266

def merge!(hash)
  hash.each do |k,v|
    @new_info[lookup_key(k)] = v
  end
  self
end

#new_record?Boolean

:nodoc:

Returns:

  • (Boolean)


191
192
193
# File 'lib/pdf/toolkit.rb', line 191

def new_record? #:nodoc:
  !@new_filename.nil?
end

#page_countObject Also known as: pages



109
110
111
112
# File 'lib/pdf/toolkit.rb', line 109

def page_count
  read_data unless @pages
  @pages
end

#pathObject Also known as: to_path

Path to the file.



116
117
118
# File 'lib/pdf/toolkit.rb', line 116

def path
  @new_filename || @filename
end

#reject!(&block) ⇒ Object

Like delete_if, only nil is returned if no attributes were removed.



241
242
243
244
245
246
247
248
249
250
251
# File 'lib/pdf/toolkit.rb', line 241

def reject!(&block)
  ensure_loaded
  ret = nil
  each do |key,value|
    if yield(key,value)
      ret = self
      delete(key)
    end
  end
  ret
end

#reloadObject

Reload (or load) the file’s metadata.



131
132
133
134
135
136
# File 'lib/pdf/toolkit.rb', line 131

def reload
  @new_info = {}
  read_data
  # run_callbacks_for(:after_load)
  self
end

#saveObject

Commit changes to the PDF. The return value is a boolean reflecting the success of the operation (This should always be true unless you’re utilizing #loot_active_record).



141
142
143
# File 'lib/pdf/toolkit.rb', line 141

def save
  create_or_update
end

#save!Object

Like save, only raise an exception if the operation fails.



146
147
148
149
150
151
152
# File 'lib/pdf/toolkit.rb', line 146

def save!
  if save
    self
  else
    raise FileNotSaved
  end
end

#save_as(filename) ⇒ Object

Save to a different file. A new object is returned if the operation succeeded. Otherwise, nil is returned.



156
157
158
159
160
# File 'lib/pdf/toolkit.rb', line 156

def save_as(filename)
  dup.save_as!(filename)
rescue FileNotSaved
  nil
end

#save_as!(filename) ⇒ Object

Save to a different file. The existing object is modified. An exception is raised if the operation fails.



164
165
166
167
168
# File 'lib/pdf/toolkit.rb', line 164

def save_as!(filename)
  @new_filename = filename
  save!
  self
end

#to_hashObject

Create a hash from the file’s metadata.



183
184
185
186
# File 'lib/pdf/toolkit.rb', line 183

def to_hash
  ensure_loaded
  @info.merge(@new_info).reject {|key,value| value.nil?}
end

#to_sObject

:nodoc:



178
179
180
# File 'lib/pdf/toolkit.rb', line 178

def to_s #:nodoc:
  "#<#{self.class}:#{path}>"
end

#to_text(filename = nil, &block) ⇒ Object

Invoke pdftotext on the file and return an IO object for reading the results.

text = my_pdf.to_text.read


174
175
176
# File 'lib/pdf/toolkit.rb', line 174

def to_text(filename = nil,&block)
  self.class.send(:pdftotext,@filename,filename,&block)
end

#update_attribute(key, value) ⇒ Object



217
218
219
220
# File 'lib/pdf/toolkit.rb', line 217

def update_attribute(key,value)
  self[key] = value
  save
end

#versionObject

Retrieve the file’s version as a symbol.

my_pdf.version # => :"1.4"


124
125
126
127
128
# File 'lib/pdf/toolkit.rb', line 124

def version
  @version ||= File.open(@filename) do |io|
    io.read(8)[5..-1].to_sym
  end
end