Browse Source

New Ruby project: PDF::FDF

master
Peter J. Jones 7 years ago
commit
c5a3e84180
10 changed files with 327 additions and 0 deletions
  1. 22
    0
      LICENSE.md
  2. 0
    0
      README.md
  3. 81
    0
      bin/pdffdf
  4. 13
    0
      lib/pdf/fdf.rb
  5. 9
    0
      lib/pdf/fdf/attributes.rb
  6. 54
    0
      lib/pdf/fdf/dump_fields_parser.rb
  7. 35
    0
      lib/pdf/fdf/field.rb
  8. 35
    0
      lib/pdf/fdf/field_loader.rb
  9. 73
    0
      lib/pdf/fdf/gen.rb
  10. 5
    0
      lib/pdf/fdf/version.rb

+ 22
- 0
LICENSE.md View File

@@ -0,0 +1,22 @@
# PDF::FDF License

Copyright (C) 2012 pmade inc. (Peter Jones pjones@pmade.com)

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:

The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

+ 0
- 0
README.md View File


+ 81
- 0
bin/pdffdf View File

@@ -0,0 +1,81 @@
#!/usr/bin/env/ruby

################################################################################
require('ostruct')
require('optparse')
require('pdf/fdf')

################################################################################
class Command

##############################################################################
DEFAULT_OPTIONS = {
:generate_fdf => false,
:load_fields => false,
:number_fields => false,
}

##############################################################################
attr_reader(:options)

##############################################################################
def initialize
@options = OpenStruct.new(DEFAULT_OPTIONS)

OptionParser.new do |p|
p.on('-h', '--help', 'Show this option summary') do
$stdout.puts(p); exit
end

p.on('-g', '--generate-fdf', 'Generate an FDF file from YAML files') do
options.generate_fdf = true
end

p.on('-l', '--load-fields', 'Load pdftk dump, generate YAML file') do
options.load_fields = true
end

p.on('-n', '--number-fields', 'Give each field a unique value') do
options.number_fields = true
end
end.parse!(ARGV)
end

##############################################################################
def run
if options.generate_fdf
generate_fdf
elsif options.load_fields
load_fields
else
raise("no operation given, see --help")
end
end

##############################################################################
private

##############################################################################
def generate_fdf
loader = PDF::FDF::FieldLoader.new
ARGV.each {|file| loader.merge(file)}

gen = PDF::FDF::Gen.new(loader.fields)
$stdout.write(gen.to_fdf)
end

##############################################################################
def load_fields
parser = PDF::FDF::DumpFieldsParser.new
parser.parse(ARGV.size == 1 ? File.open(ARGV.first) : $stdin)
$stdout.puts(parser.generate_yaml(options.number_fields))
end
end

################################################################################
begin
Command.new.run
rescue RuntimeError => e
$stderr.puts(File.basename($0) + ": ERROR: #{e}")
exit(1)
end

+ 13
- 0
lib/pdf/fdf.rb View File

@@ -0,0 +1,13 @@
################################################################################
require('yaml')

################################################################################
module PDF
module FDF
autoload('Attributes', 'pdf/fdf/attributes')
autoload('Field', 'pdf/fdf/field')
autoload('FieldLoader', 'pdf/fdf/field_loader')
autoload('DumpFieldsParser', 'pdf/fdf/dump_fields_parser')
autoload('Gen', 'pdf/fdf/gen')
end
end

+ 9
- 0
lib/pdf/fdf/attributes.rb View File

@@ -0,0 +1,9 @@
module PDF::FDF::Attributes

##############################################################################
def attributes= (attrs={})
attrs.each do |key, value|
send("#{key}=", value)
end
end
end

+ 54
- 0
lib/pdf/fdf/dump_fields_parser.rb View File

@@ -0,0 +1,54 @@
class PDF::FDF::DumpFieldsParser

##############################################################################
attr_reader(:fields)

##############################################################################
def initialize
@fields = []
end

##############################################################################
def parse (io)
current_field = nil

io.each_line do |line|
if line.match(/^---\s*$/)
@fields << current_field if current_field
current_field = PDF::FDF::Field.new
elsif m = line.match(/^([^:]+):\s*(.*)$/)
current_field ||= PDF::FDF::Field.new
set_field_value(current_field, m[1], m[2])
else
raise("don't know how to parse: #{line}")
end
end

@fields
end

##############################################################################
def generate_yaml (number_fields=false)
@fields.each_with_index {|f, i| f.value = i.to_s} if number_fields
@fields.map {|f| f.to_hash}.to_yaml
end

##############################################################################
private

##############################################################################
def set_field_value (field, key, value)
case key
when 'FieldType'
field.type = value
when 'FieldName'
field.name = value
when 'FieldFlags'
field.flags = value.to_i
when 'FieldMaxLength'
field.max_length = value.to_i
when 'FieldStateOption'
field.options << value
end
end
end

+ 35
- 0
lib/pdf/fdf/field.rb View File

@@ -0,0 +1,35 @@
class PDF::FDF::Field

##############################################################################
include(PDF::FDF::Attributes)

##############################################################################
attr_accessor(:name, :alias, :value, :type, :flags, :max_length, :options)

##############################################################################
def initialize (attributes={})
attrs = {
'name' => '',
'alias' => '',
'value' => '',
'type' => 'Text',
'flags' => 0,
'max_length' => 0,
'options' => [],
}.merge(attributes)

self.attributes = attrs
end

##############################################################################
def to_hash
h = instance_variables.inject({}) do |hash, name|
hash[name.sub('@', '')] = instance_variable_get(name)
hash
end

h.delete('max_length') if max_length.zero?
h.delete('options') if options.empty?
h
end
end

+ 35
- 0
lib/pdf/fdf/field_loader.rb View File

@@ -0,0 +1,35 @@
class PDF::FDF::FieldLoader

##############################################################################
attr_reader(:fields)

##############################################################################
def initialize (file=nil)
@fields = []
merge(file) if file
end

##############################################################################
def merge (file)
Array(YAML.load_file(file)).each do |new_field|
if old_field = find(new_field)
old_field.attributes = new_field
else
@fields << PDF::FDF::Field.new(new_field)
end
end

@fields
end

##############################################################################
private

##############################################################################
def find (new_field)
@fields.detect do |old_field|
(!new_field['name'].empty? && new_field['name'] == old_field.name) ||
(!new_field['alias'].empty? && new_field['alias'] == old_field.alias)
end
end
end

+ 73
- 0
lib/pdf/fdf/gen.rb View File

@@ -0,0 +1,73 @@
################################################################################
#
# Portions of this file are: Copyright (c) 2009-2011 Jens Kraemer
#
# Permission is hereby granted, free of charge, to any person obtaining
# a copy of this software and associated documentation files (the
# 'Software'), to deal in the Software without restriction, including
# without limitation the rights to use, copy, modify, merge, publish,
# distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so, subject to
# the following conditions:
#
# The above copyright notice and this permission notice shall be
# included in all copies or substantial portions of the Software.
#
# THE SOFTWARE IS PROVIDED 'AS IS', WITHOUT WARRANTY OF ANY KIND,
# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
# IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
################################################################################
class PDF::FDF::Gen

##############################################################################
def initialize (fields)
@fields = fields
end

##############################################################################
def to_fdf
header + @fields.map {|f| encode_field(f)}.join + footer
end

##############################################################################
private

##############################################################################
def header
"%FDF-1.2\n\n1 0 obj\n<<\n/FDF << /Fields 2 0 R >>\n>>\nendobj\n2 0 obj\n["
end

##############################################################################
def footer
"]\nendobj\ntrailer\n<<\n/Root 1 0 R\n\n>>\n%%EOF\n"
end

##############################################################################
def encode_field (field)
results = "<</T(#{field.name})/V"

results <<
if field.value.is_a?(Array)
'[' + field.value.map {|v| "(#{quote(v)})"}.join + ']'
else
"(#{quote(field.value)})"
end

results << ">>\n"
results
end

##############################################################################
def quote (value)
value.to_s.strip.
gsub(/\\/, '\\').
gsub(/\(/, '\(').
gsub(/\)/, '\)').
gsub(/\n/, '\r')
end
end

+ 5
- 0
lib/pdf/fdf/version.rb View File

@@ -0,0 +1,5 @@
module PDF
module FDF
VERSION = '0.1.0'
end
end

Loading…
Cancel
Save