Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
21 changes: 21 additions & 0 deletions History.txt
Original file line number Diff line number Diff line change
@@ -1,3 +1,24 @@
== 0.3.6 2012-10-25
* use java_import instead of include_class (include_class deprecated in jruby 1.7.0)

== 0.3.5 2012-06-27
* Checkboxes now work in JRuby

== 0.3.4 2010-09-24
* Circle/ellipse/rectangle now take a page parameter, and can be applied to a specific page.
This is useful for multi-page PDFs.

== 0.3.3 2010-09-24
* iText downgraded to 4.2.0 due to license incompatibility

== 0.3.2 2010-09-24
* Added support for drawing circles, rectangles and ellipses

== 0.3.1 2010-09-15
* checkbox support added
* iText updated to 5.0.4
* documentation updated and typos fixed

== 0.3.0 2009-02-08

* Refactored the code.
Expand Down
2 changes: 1 addition & 1 deletion Manifest.txt
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ History.txt
Manifest.txt
README.txt
Rakefile
ext/iText-2.1.4.jar
ext/iText-4.2.0.jar
lib/pdf/stamper.rb
lib/pdf/stamper/jruby.rb
lib/pdf/stamper/rjb.rb
Expand Down
21 changes: 14 additions & 7 deletions README.txt
Original file line number Diff line number Diff line change
@@ -1,36 +1,43 @@
= pdf/stamper - PDF Templates, Wow!
= pdf/stamper - PDF Templates
http://github.com/jaywhy/pdf-stamper/
by Jason Yates

15 September 2010 -- fork by Paul Schreiber
http://github.com/paulschreiber/pdf-stamper/

== DESCRIPTION:

Super cool PDF templates using iText's PdfStamper.
Fill out PDF forms (templates) using iText's PdfStamper.

== CAVEAT:

Anything super cool must have a caveat. You have to use JRuby or RJB. Plus you
can only use Adobe LiveCycle Designer to create the templates.
You have to use JRuby or RJB. You need Adobe LiveCycle Designer
or Acrobat Professional to create the templates.

== EXAMPLE:
pdf = PDF::Stamper.new("my_template.pdf")
pdf.text :first_name, "Jason"
pdf.text :last_name, "Yates"
pdf.image :photo, "photo.jpg"
pdf.checkbox :hungry
pdf.ellipse(140, 380, 50, 13)
pdf.rectangle(140, 380, 50, 13, 2)
pdf.circle(140, 380)
pdf.save_as "my_output.pdf"

== INSTALL:

$ sudo gem install pdf-stamper
$ sudo gem install ps-pdf-stamper

== CODE:

$ git clone http://github.com/jaywhy/pdf-stamper/
$ git clone http://github.com/paulschreiber/pdf-stamper/

== LICENSE:

(The MIT License)

Copyright (c) 2007-2009 Jason Yates
Copyright 2007-2010 Jason Yates, Paul Schreiber

Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
Expand Down
8 changes: 4 additions & 4 deletions Rakefile
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ require 'spec/rake/spectask'
%w[rubygems rake rake/clean fileutils newgem rubigen].each { |f| require f }

$hoe = Hoe.new('pdf-stamper', PDF::Stamper::VERSION) do |p|
p.name = 'pdf-stamper'
p.author = 'Jason Yates'
p.email = 'jaywhy@gmail.com'
p.summary = "Super cool PDF templates using iText's PdfStamper."
p.name = 'ps-pdf-stamper'
p.author = 'Paul Schreiber'
p.email = 'paulschreiber@gmail.com'
p.summary = "PDF templates using iText's PdfStamper."
p.description = p.paragraphs_of('README.txt', 2..5).join("\n\n")
p.changes = p.paragraphs_of("History.txt", 0..1).join("\n\n")
p.extra_dev_deps = [
Expand Down
Binary file removed ext/iText-2.1.4.jar
Binary file not shown.
Binary file added ext/iText-4.2.0.jar
Binary file not shown.
57 changes: 49 additions & 8 deletions lib/pdf/stamper.rb
Original file line number Diff line number Diff line change
Expand Up @@ -10,49 +10,90 @@

module PDF
class Stamper
VERSION = "0.3.0"
VERSION = "0.3.6"

if RUBY_PLATFORM =~ /java/ # ifdef to check if your using JRuby
require 'pdf/stamper/jruby'
else
require 'pdf/stamper/rjb'
end
# PDF::Stamper provides an interface into iText's PdfStamper allowing for the
# editing of existing PDF's as templates. PDF::Stamper is not a PDF generator,
# it allows you to edit existing PDF's and use them as templates.
# editing of existing PDFs as templates. PDF::Stamper is not a PDF generator,
# it allows you to edit existing PDFs and use them as templates.
#
# == Creation of templates
#
# Templates currently can only be created using Adobe LiveCycle
# Designer which comes with the lastest versions of Adobe Acrobat
# Professional. Using LiveCycle Designer you can create a form and
# add textfield's for text and button's for images.
# Templates currently can be created using Adobe LiveCycle Designer
# or Adobe Acrobat Professional. Using Acrobat Professional, you can create
# a form and add textfields, checkboxes, radio buttons and buttons for images.
#
# == Example
#
# pdf = PDF::Stamper.new("my_template.pdf")
# pdf.text :first_name, "Jason"
# pdf.text :last_name, "Yates"
# pdf.image :photo, "photo.jpg"
# pdf.checkbox :hungry
# pdf.save_as "my_output"

# Set a textfield defined by key and text to value.
def text(key, value)
@form.setField(key.to_s, value.to_s) # Value must be a string or itext will error.
end

# Set a checkbox to checked
def checkbox(key)
field_type = @form.getFieldType(key.to_s)
return unless is_checkbox(field_type)

all_states = @form.getAppearanceStates(key.to_s)
yes_state = all_states.reject{|x| x == "Off"}


@form.setField(key.to_s, yes_state.first) unless (yes_state.size == 0)
end

# Get checkbox values
def get_checkbox_values(key)
field_type = @form.getFieldType(key.to_s)
return unless is_checkbox(field_type)

@form.getAppearanceStates(key.to_s)
end

def circle(x, y, r, page=1)
update_canvas_list(page)
@canvas_list[page].circle(x, y, r)
end

def ellipse(x, y, width, height, page=1)
update_canvas_list(page)
@canvas_list[page].ellipse(x, y, x + width, y + height)
end

def rectangle(x, y, width, height, page=1)
update_canvas_list(page)
@canvas_list[page].rectangle(x, y, width, height)
end

# Saves the PDF into a file defined by path given.
def save_as(file)
File.open(file, "wb") { |f| f.write to_s }
end

private

def update_canvas_list(page)
@canvas_list[page] = @stamp.getOverContent(page) unless @canvas_list.has_key?(page)
end

def fill
@canvas_list.values.each do |c|
c.stroke
end
@stamp.setFormFlattening(true)
@stamp.close
end
end
end


23 changes: 15 additions & 8 deletions lib/pdf/stamper/jruby.rb
Original file line number Diff line number Diff line change
Expand Up @@ -4,15 +4,16 @@

$:.unshift(File.join(File.dirname(__FILE__), '..', '..', '..', 'ext'))
require 'java'
require 'iText-2.1.4.jar'
require 'iText-4.2.0.jar'

include_class 'java.io.FileOutputStream'
include_class 'java.io.ByteArrayOutputStream'
include_class 'com.lowagie.text.pdf.AcroFields'
include_class 'com.lowagie.text.pdf.PdfReader'
include_class 'com.lowagie.text.pdf.PdfStamper'
include_class 'com.lowagie.text.Image'
include_class 'com.lowagie.text.Rectangle'
java_import 'java.io.FileOutputStream'
java_import 'java.io.ByteArrayOutputStream'
java_import 'com.lowagie.text.pdf.AcroFields'
java_import 'com.lowagie.text.pdf.PdfReader'
java_import 'com.lowagie.text.pdf.PdfStamper'
java_import 'com.lowagie.text.Image'
java_import 'com.lowagie.text.Rectangle'
java_import 'com.lowagie.text.pdf.GrayColor'

module PDF
class Stamper
Expand All @@ -28,6 +29,12 @@ def template(template)
@baos = ByteArrayOutputStream.new
@stamp = PdfStamper.new(reader, @baos)#FileOutputStream.new(@tmp_path))
@form = @stamp.getAcroFields()
@black = GrayColor.new(0.0)
@canvas_list = { 1 => @stamp.getOverContent(1) }
end

def is_checkbox(field_type)
field_type == AcroFields::FIELD_TYPE_CHECKBOX
end

# Set a button field defined by key and replaces with an image.
Expand Down
77 changes: 71 additions & 6 deletions lib/pdf/stamper/rjb.rb
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
require 'rubygems'
require 'rjb'

Rjb::load(File.join(File.dirname(__FILE__), '..', '..', '..', 'ext', 'iText-2.1.4.jar'), ['-Djava.awt.headless=true'])
Rjb::load(File.join(File.dirname(__FILE__), '..', '..', '..', 'ext', 'iText-4.2.0.jar'), ['-Djava.awt.headless=true'])

module PDF
# PDF::Stamper::RJB
Expand All @@ -24,27 +24,40 @@ def initialize(pdf = nil, options = {})
@acrofields = Rjb::import('com.lowagie.text.pdf.AcroFields')
@pdfreader = Rjb::import('com.lowagie.text.pdf.PdfReader')
@pdfstamper = Rjb::import('com.lowagie.text.pdf.PdfStamper')
@pdfwriter = Rjb::import('com.lowagie.text.pdf.PdfWriter')
@image_class = Rjb::import('com.lowagie.text.Image')
@pdf_content_byte_class = Rjb::import('com.lowagie.text.pdf.PdfContentByte')
@basefont_class = Rjb::import('com.lowagie.text.pdf.BaseFont')
@rectangle = Rjb::import('com.lowagie.text.Rectangle')
@gray_color = Rjb::import('com.lowagie.text.pdf.GrayColor')

template(pdf) if ! pdf.nil?
end

def is_checkbox(field_type)
field_type == @acrofields.FIELD_TYPE_CHECKBOX
end

def template(template)
reader = @pdfreader.new(template)
@pagesize = reader.getPageSize(1)
@numpages = reader.getNumberOfPages()
@baos = @bytearray.new
@stamp = @pdfstamper.new(reader, @baos)
@form = @stamp.getAcroFields()
@black = @gray_color.new(0.0)
@canvas_list = { 1 => @stamp.getOverContent(1) }
end

# Set a button field defined by key and replaces with an image.
def image(key, image_path)
# Idea from here http://itext.ugent.be/library/question.php?id=31
# Thanks Bruno for letting me know about it.
image = Rjb::import('com.lowagie.text.Image')
img = image.getInstance(image_path)
img = @image_class.getInstance(image_path)
img_field = @form.getFieldPositions(key.to_s)

rectangle = Rjb::import('com.lowagie.text.Rectangle')
rect = rectangle.new(img_field[1], img_field[2], img_field[3], img_field[4])

rect = @rectangle.new(img_field[1], img_field[2], img_field[3], img_field[4])
img.scaleToFit(rect.width, rect.height)
img.setAbsolutePosition(
img_field[1] + (rect.width - img.getScaledWidth) / 2,
Expand All @@ -55,11 +68,63 @@ def image(key, image_path)
cb.addImage(img)
end

# Takes the PDF output and sends as a string. Basically it's sole
# Takes the PDF output and sends as a string. Basically its sole
# purpose is to be used with send_data in rails.
def to_s
fill
@baos.toByteArray
end

def add_images(images)
basefont = @basefont_class.createFont(@basefont_class.HELVETICA, @basefont_class.CP1252, @basefont_class.NOT_EMBEDDED)
image_size = []
half_page_width = @pagesize.width() / 2
half_page_height = @pagesize.height() / 2
image_size[0] = half_page_width - 80
image_size[1] = half_page_height - 80
pages = (images.length / 4.0).ceil
pages.times do |index|
page_number = index + @numpages + 1
image_index = index * 4
@stamp.insertPage(page_number, @pagesize)
over = @stamp.getOverContent(page_number)
over.setFontAndSize(basefont, 12.0)
4.times do |n|
if pdf_image = images[image_index + n]
if image_path = pdf_image[0]
img = @image_class.getInstance(image_path)
img.scaleToFit(image_size[0] + 30, (image_size[1]))
img_x_offset = (half_page_width - image_size[0]) / 2
img_y_offset = (half_page_height - img.getScaledHeight()) / 2
case n
when 0
img.setAbsolutePosition(img_x_offset, (half_page_height + img_y_offset))
when 1
img.setAbsolutePosition((half_page_width + (img_x_offset - 30)), (half_page_height + img_y_offset))
when 2
img.setAbsolutePosition(img_x_offset, img_y_offset)
when 3
img.setAbsolutePosition((half_page_width + (img_x_offset - 30)), img_y_offset)
end
over.addImage(img)
end
if image_label = pdf_image[1]
over.beginText()
over.showTextAligned(@pdf_content_byte_class.ALIGN_CENTER, image_label, (img.getAbsoluteX() + ((image_size[0] + 30) / 2)), (img.getAbsoluteY() - 15), 0)
over.endText()
end
end
end
end
@stamp.setFullCompression()
end

def add_image_on_page(page, x, y, url)
over = @stamp.getOverContent(page)
img = @image_class.getInstance(url)
img.setAbsolutePosition(x,y)
img.scaleToFit(200,70)
over.addImage(img)
end
end
end
19 changes: 9 additions & 10 deletions pdf-stamper.gemspec
Original file line number Diff line number Diff line change
@@ -1,23 +1,22 @@
# -*- encoding: utf-8 -*-

Gem::Specification.new do |s|
s.name = %q{pdf-stamper}
s.version = "0.3.0"
s.name = %q{ps-pdf-stamper}
s.version = "0.3.6"

s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
s.authors = ["Jason Yates"]
s.date = %q{2009-02-08}
s.description = %q{Super cool PDF templates using iText's PdfStamper. == CAVEAT: Anything super cool must have a caveat. You have to use JRuby or RJB. Plus you can only use Adobe LiveCycle Designer to create the templates. == EXAMPLE: pdf = PDF::Stamper.new("my_template.pdf") pdf.text :first_name, "Jason" pdf.text :last_name, "Yates" pdf.image :photo, "photo.jpg" pdf.save_as "my_output.pdf"}
s.email = %q{jaywhy@gmail.com}
s.authors = ["Paul Schreiber"]
s.date = %q{2012-10-25}
s.description = %q{Fill out PDF forms (templates) using iText's PdfStamper. == CAVEAT: You have to use JRuby or RJB. You need Adobe LiveCycle Designer or Acrobat Professional to create the templates. == EXAMPLE: pdf = PDF::Stamper.new("my_template.pdf") pdf.text :first_name, "Jason" pdf.text :last_name, "Yates" pdf.image :photo, "photo.jpg" pdf.checkbox :hungry pdf.save_as "my_output.pdf"}
s.email = %q{paulschreiber@gmail.com}
s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.txt"]
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/iText-2.1.4.jar", "lib/pdf/stamper.rb", "lib/pdf/stamper/jruby.rb", "lib/pdf/stamper/rjb.rb", "spec/logo.gif", "spec/pdf_stamper_spec.rb", "spec/test_template.pdf"]
s.has_rdoc = true
s.homepage = %q{ http://github.com/jaywhy/pdf-stamper/}
s.files = ["History.txt", "Manifest.txt", "README.txt", "Rakefile", "ext/iText-4.2.0.jar", "lib/pdf/stamper.rb", "lib/pdf/stamper/jruby.rb", "lib/pdf/stamper/rjb.rb", "spec/logo.gif", "spec/pdf_stamper_spec.rb", "spec/test_template.pdf"]
s.homepage = %q{http://github.com/paulschreiber/pdf-stamper/}
s.rdoc_options = ["--main", "README.txt"]
s.require_paths = ["lib", "ext"]
s.rubyforge_project = %q{pdf-stamper}
s.rubygems_version = %q{1.3.1}
s.summary = %q{Super cool PDF templates using iText's PdfStamper.}
s.summary = %q{PDF templates using iText's PdfStamper.}

if s.respond_to? :specification_version then
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
Expand Down