pdf_utils 0.1.0
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/Rakefile +29 -0
- data/VERSION +1 -0
- data/lib/in_tempdir.rb +29 -0
- data/lib/pdf_utils.rb +175 -0
- data/lib/pdf_utils/color.rb +27 -0
- data/lib/pdf_utils/info.rb +46 -0
- data/script/check_system_dependencies +62 -0
- data/spec/fixtures/marketing.pdf +0 -0
- data/spec/fixtures/page.pdf +0 -0
- data/spec/pdf_utils/color_spec.rb +15 -0
- data/spec/pdf_utils/info_spec.rb +24 -0
- data/spec/pdf_utils_spec.rb +129 -0
- data/spec/spec_helper.rb +20 -0
- metadata +78 -0
data/Rakefile
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
begin
|
2
|
+
require 'jeweler'
|
3
|
+
Jeweler::Tasks.new do |gemspec|
|
4
|
+
gemspec.name = "pdf_utils"
|
5
|
+
gemspec.summary = "PdfUtils abstracts a lot of well working UNIX tools for PDF files"
|
6
|
+
gemspec.description = <<-DESC
|
7
|
+
Requires xpdf, pdftk, swftools/pdf2swf and imagemagick.
|
8
|
+
You can check their functionality by running `$ rake check_system_dependencies´.
|
9
|
+
DESC
|
10
|
+
gemspec.email = "l.rieder@gmail.com"
|
11
|
+
gemspec.homepage = "http://github.com/Overbryd/pdf_utils"
|
12
|
+
gemspec.authors = ["Lukas Rieder", "Andreas Korth"]
|
13
|
+
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler not available. Install it with: gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'spec/rake/spectask'
|
20
|
+
|
21
|
+
desc "Run all examples"
|
22
|
+
Spec::Rake::SpecTask.new('spec') do |t|
|
23
|
+
t.spec_opts = ['--colour', '--format specdoc']
|
24
|
+
t.spec_files = FileList['spec/**/*_spec.rb']
|
25
|
+
end
|
26
|
+
|
27
|
+
task :check_system_dependencies do
|
28
|
+
load File.join(File.dirname(__FILE__), 'script', 'check_system_dependencies')
|
29
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.1.0
|
data/lib/in_tempdir.rb
ADDED
@@ -0,0 +1,29 @@
|
|
1
|
+
require 'tmpdir'
|
2
|
+
|
3
|
+
module InTmpdir
|
4
|
+
|
5
|
+
private
|
6
|
+
|
7
|
+
def in_tmpdir(dirname='tmp')
|
8
|
+
dirname = tmp_file_name(dirname)
|
9
|
+
FileUtils.mkdir_p(dirname) unless File.directory?(dirname)
|
10
|
+
begin
|
11
|
+
yield(dirname)
|
12
|
+
ensure
|
13
|
+
FileUtils.rm_rf(dirname) if File.exists?(dirname)
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def with_tmpfile(filename='tmp')
|
18
|
+
filename = tmp_file_name(filename)
|
19
|
+
begin
|
20
|
+
yield(filename)
|
21
|
+
ensure
|
22
|
+
FileUtils.rm_rf(filename) if File.exists?(filename)
|
23
|
+
end
|
24
|
+
end
|
25
|
+
|
26
|
+
def tmp_file_name(name='tmp')
|
27
|
+
File.join(Dir.tmpdir, [$$.to_s(16), object_id.to_s(16), name].join('_'))
|
28
|
+
end
|
29
|
+
end
|
data/lib/pdf_utils.rb
ADDED
@@ -0,0 +1,175 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'active_support'
|
3
|
+
require 'prawn'
|
4
|
+
require 'pdf/reader'
|
5
|
+
|
6
|
+
require 'in_tempdir'
|
7
|
+
require 'pdf_utils/info'
|
8
|
+
require 'pdf_utils/color'
|
9
|
+
|
10
|
+
module PdfUtils
|
11
|
+
|
12
|
+
class << self
|
13
|
+
|
14
|
+
include InTmpdir
|
15
|
+
|
16
|
+
def objects(filename, filter={})
|
17
|
+
uncompress(filename) do |uncompressed|
|
18
|
+
PDF::Hash.new(uncompressed).values.select do |obj|
|
19
|
+
if obj.kind_of?(Hash)
|
20
|
+
if obj.has_key?(:Contents) && obj[:Contents].kind_of?(String)
|
21
|
+
obj[:Contents] = Iconv.conv('utf-8', 'utf-16', obj[:Contents])
|
22
|
+
end
|
23
|
+
filter.detect {|k, v| obj[k] == v }
|
24
|
+
end
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
def annotations(filename)
|
30
|
+
objects(filename, :Type => :Annot)
|
31
|
+
end
|
32
|
+
|
33
|
+
def info(filename)
|
34
|
+
PdfUtils::Info.new(filename)
|
35
|
+
end
|
36
|
+
|
37
|
+
def toc(filename)
|
38
|
+
toc = []
|
39
|
+
if meta_data = run_command(:pdftk, "#{filename} dump_data")
|
40
|
+
entry = nil
|
41
|
+
meta_data.scan(/^Bookmark(\w+): (.*)$/) do |(key, value)|
|
42
|
+
case key
|
43
|
+
when "Title"
|
44
|
+
entry = [value]
|
45
|
+
when "Level"
|
46
|
+
entry << value.to_i
|
47
|
+
when "PageNumber"
|
48
|
+
if value.to_i > 0
|
49
|
+
entry << value.to_i
|
50
|
+
toc << entry
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
toc
|
56
|
+
end
|
57
|
+
|
58
|
+
def to_text(filename, target = nil)
|
59
|
+
run_command(:pdftotext, "-layout -enc UTF-8 #{filename} #{target || '-'}", !!target)
|
60
|
+
end
|
61
|
+
|
62
|
+
def to_swf(source, target)
|
63
|
+
run_command(:pdf2swf, "-T 9 -f -s transparent -s detectspaces #{source} -o #{target}")
|
64
|
+
end
|
65
|
+
|
66
|
+
def uncompress(source, target=nil, &block)
|
67
|
+
target ||= tmp_file_name("uncompress")
|
68
|
+
run_command(:pdftk, "#{source} output #{target} uncompress")
|
69
|
+
if block_given?
|
70
|
+
begin
|
71
|
+
yield(target)
|
72
|
+
ensure
|
73
|
+
FileUtils.rm(target)
|
74
|
+
end
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
def slice(source, from_page, to_page, target)
|
79
|
+
run_command(:pdftk, "#{source} cat #{from_page}-#{to_page} output #{target}")
|
80
|
+
end
|
81
|
+
|
82
|
+
def slice!(source, from_page, to_page)
|
83
|
+
target = tmp_file_name("slice")
|
84
|
+
slice(source, from_page, to_page, target)
|
85
|
+
FileUtils.mv(target, source)
|
86
|
+
end
|
87
|
+
|
88
|
+
def burst(source, target)
|
89
|
+
run_command(:pdftk, "#{source} burst output #{target}")
|
90
|
+
end
|
91
|
+
|
92
|
+
def cat(source, target)
|
93
|
+
run_command(:pdftk, "#{source} cat output #{target}")
|
94
|
+
end
|
95
|
+
|
96
|
+
def watermark(source, target, options = {}, &block)
|
97
|
+
raise ArgumentError.new("No block given") unless block_given?
|
98
|
+
options[:page_size] ||= info(source).page_dimensions
|
99
|
+
with_tmpfile("watermark") do |watermarked|
|
100
|
+
Prawn::Document.generate(watermarked, options, &block)
|
101
|
+
run_command(:pdftk, "#{source} background #{watermarked} output #{target}")
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
def watermark!(source, options = {}, &block)
|
106
|
+
target = tmp_file_name("watermark_merge")
|
107
|
+
watermark(source, target, options, &block)
|
108
|
+
FileUtils.mv(target, source)
|
109
|
+
end
|
110
|
+
|
111
|
+
def annotate(source, annotations, target, options = {})
|
112
|
+
options[:page_size] ||= info(source).page_dimensions
|
113
|
+
with_tmpfile("annotate") do |annotated|
|
114
|
+
Prawn::Document.generate(annotated, options) do |pdf|
|
115
|
+
annotations.each do |annotation|
|
116
|
+
pdf.annotate(annotation)
|
117
|
+
end
|
118
|
+
end
|
119
|
+
run_command(:pdftk, "#{annotated} background #{source} output #{target}")
|
120
|
+
end
|
121
|
+
end
|
122
|
+
|
123
|
+
def annotate!(source, annotations, options = {})
|
124
|
+
target = tmp_file_name("annotate_merge")
|
125
|
+
annotate(source, annotations, target, options)
|
126
|
+
FileUtils.mv(target, source)
|
127
|
+
end
|
128
|
+
|
129
|
+
THUMBNAIL_DEFAULTS = { :density => 150, :size => '50%', :format => 'jpg', :quality => 85, :target => nil, :page => 1 }.freeze
|
130
|
+
|
131
|
+
def thumbnail(source, options = {})
|
132
|
+
options.assert_valid_keys(THUMBNAIL_DEFAULTS.keys)
|
133
|
+
|
134
|
+
options = THUMBNAIL_DEFAULTS.merge(options)
|
135
|
+
target = options[:target] || source.sub(/(\.\w+)?$/, ".#{options[:format]}")
|
136
|
+
source = "#{source}[#{options[:page].to_i-1}]"
|
137
|
+
|
138
|
+
run_command(:convert, [
|
139
|
+
'-density' , options[:density],
|
140
|
+
source,
|
141
|
+
'-colorspace' , :rgb,
|
142
|
+
'-thumbnail' , options[:size],
|
143
|
+
'-quality' , options[:quality],
|
144
|
+
target
|
145
|
+
].join(' '))
|
146
|
+
return target
|
147
|
+
end
|
148
|
+
|
149
|
+
SNAPSHOT_DEFAULTS = { :density => 150, :compress => 'JPEG', :quality => 85 }.freeze
|
150
|
+
|
151
|
+
def snapshot(source, target, options = {})
|
152
|
+
options.assert_valid_keys(SNAPSHOT_DEFAULTS.keys + [:page])
|
153
|
+
page_number = (options.delete(:page) || 1).to_i
|
154
|
+
source = "#{source}[#{page_number-1}]"
|
155
|
+
options = SNAPSHOT_DEFAULTS.merge(options).map{ |opt,val| "-#{opt} #{val}" } << "#{source} #{target}"
|
156
|
+
run_command(:convert, options)
|
157
|
+
end
|
158
|
+
|
159
|
+
def snapshot!(source, options = {})
|
160
|
+
snapshot(source, source, options)
|
161
|
+
end
|
162
|
+
|
163
|
+
def run_command(command, args, reroute_errors = true)
|
164
|
+
command = [command, args]
|
165
|
+
command << '2>&1' if reroute_errors
|
166
|
+
command = command.join(' ')
|
167
|
+
output = `#{command}`
|
168
|
+
if $?.success?
|
169
|
+
output
|
170
|
+
else
|
171
|
+
raise RuntimeError.new("Command failed: #{command}\n#{output}")
|
172
|
+
end
|
173
|
+
end
|
174
|
+
end
|
175
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
module PdfUtils
|
2
|
+
class Color
|
3
|
+
def initialize(*args)
|
4
|
+
if args.first.is_a?(String)
|
5
|
+
@r, @g, @b = args.first.scan(/../).map{ |rgb| rgb.to_i(16) }
|
6
|
+
elsif args.size == 3
|
7
|
+
if args.any? {|arg| arg.kind_of?(Float) }
|
8
|
+
@r, @g, @b = args.map {|v| (v * 255).to_i }
|
9
|
+
else
|
10
|
+
@r, @g, @b = args
|
11
|
+
end
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def to_pdf
|
16
|
+
to_rgb.map{ |v| v / 255.0 }
|
17
|
+
end
|
18
|
+
|
19
|
+
def to_hex
|
20
|
+
to_rgb.inject(''){ |hex, v| hex << "%02x" % v }
|
21
|
+
end
|
22
|
+
|
23
|
+
def to_rgb
|
24
|
+
[@r, @g, @b]
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
@@ -0,0 +1,46 @@
|
|
1
|
+
module PdfUtils
|
2
|
+
class Info
|
3
|
+
attr_reader :pdf_version, :title, :author, :subject, :keywords, :creator, :producer, :tagged, :optimized, :encrypted
|
4
|
+
attr_reader :file_size, :mod_date, :creation_date, :pages, :page_size, :page_format
|
5
|
+
alias_method :tagged?, :tagged
|
6
|
+
alias_method :optimized?, :optimized
|
7
|
+
alias_method :encrypted?, :encrypted
|
8
|
+
alias_method :modification_date, :mod_date
|
9
|
+
|
10
|
+
def initialize(filename)
|
11
|
+
raise ArgumentError.new("File does not exist: #{filename}") unless File.exist?(filename)
|
12
|
+
info = {}
|
13
|
+
PdfUtils::run_command(:pdfinfo, filename).scan(/^([^:]+): +(.*?)?$/) do |property|
|
14
|
+
info.store(*property)
|
15
|
+
end
|
16
|
+
@pdf_version = info["PDF version"]
|
17
|
+
@title = info["Title"]
|
18
|
+
@subject = info["Subject"]
|
19
|
+
@keywords = info["Keywords"]
|
20
|
+
@author = info["Author"]
|
21
|
+
@creator = info["Creator"]
|
22
|
+
@producer = info["Producer"]
|
23
|
+
@pages = info["Pages"].to_i
|
24
|
+
@creation_date = Time.parse(info["CreationDate"]) rescue nil
|
25
|
+
@mod_date = Time.parse(info["ModDate"]) rescue nil
|
26
|
+
@page_size = info["Page size"] =~ /^([\d.]+) x ([\d.]+)/ && [$1.to_f, $2.to_f]
|
27
|
+
@page_format = info["Page size"] =~ /\(([^(]+)\)$/ && $1
|
28
|
+
@file_size = info["File size"] =~ /^(\d+) bytes$/ && $1.to_i
|
29
|
+
@optimized = info["Optimized"] == 'yes'
|
30
|
+
@tagged = info["Tagged"] == 'yes'
|
31
|
+
@encrypted = info["Encrypted"] == 'yes'
|
32
|
+
end
|
33
|
+
|
34
|
+
def page_dimensions
|
35
|
+
[page_width, page_height]
|
36
|
+
end
|
37
|
+
|
38
|
+
def page_width
|
39
|
+
@page_size[0]
|
40
|
+
end
|
41
|
+
|
42
|
+
def page_height
|
43
|
+
@page_size[1]
|
44
|
+
end
|
45
|
+
end
|
46
|
+
end
|
@@ -0,0 +1,62 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
$:.unshift(File.join(File.dirname(__FILE__), '../lib'))
|
3
|
+
require 'pdf_utils'
|
4
|
+
|
5
|
+
tmpdir = File.join(Dir.tmpdir, "#{$$}-dependency_checks")
|
6
|
+
FileUtils.mkdir(tmpdir) rescue nil
|
7
|
+
|
8
|
+
root = File.join(File.dirname(__FILE__), '../')
|
9
|
+
checkfile = File.join(tmpdir, 'check.pdf')
|
10
|
+
FileUtils.cp(File.join(root, 'spec/fixtures/marketing.pdf'), checkfile)
|
11
|
+
|
12
|
+
def check(what, &block)
|
13
|
+
print "Checking #{what}... "
|
14
|
+
yield
|
15
|
+
if $?.success?
|
16
|
+
puts "passed."
|
17
|
+
else
|
18
|
+
puts "failed."
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
check 'pdf info' do
|
23
|
+
PdfUtils::info(checkfile)
|
24
|
+
end
|
25
|
+
|
26
|
+
check 'pdf table of contents' do
|
27
|
+
PdfUtils::toc(checkfile)
|
28
|
+
end
|
29
|
+
|
30
|
+
check 'pdf to text' do
|
31
|
+
PdfUtils::to_text(checkfile)
|
32
|
+
end
|
33
|
+
|
34
|
+
check 'pdf uncompress' do
|
35
|
+
PdfUtils::uncompress(checkfile)
|
36
|
+
end
|
37
|
+
|
38
|
+
check 'pdf to swf' do
|
39
|
+
PdfUtils::to_swf(checkfile, File.join(tmpdir, 'check.swf'))
|
40
|
+
end
|
41
|
+
|
42
|
+
check 'pdf slicing' do
|
43
|
+
PdfUtils::slice(checkfile, 1, 2, File.join(tmpdir, 'sliced.pdf'))
|
44
|
+
end
|
45
|
+
|
46
|
+
check 'pdf bursting' do
|
47
|
+
PdfUtils::burst(checkfile, File.join(tmpdir, 'burst-%04d.pdf'))
|
48
|
+
end
|
49
|
+
|
50
|
+
check 'pdf background' do
|
51
|
+
PdfUtils::watermark(checkfile, File.join(tmpdir, 'watermarked.pdf'), :margin => 0) do |page|
|
52
|
+
page.text 'I am watermarked'
|
53
|
+
end
|
54
|
+
end
|
55
|
+
|
56
|
+
check 'pdf to cover' do
|
57
|
+
PdfUtils::thumbnail(checkfile, :target => File.join(tmpdir, 'cover.jpg'))
|
58
|
+
end
|
59
|
+
|
60
|
+
check 'pdf to snapshot' do
|
61
|
+
PdfUtils::snapshot(checkfile, File.join(tmpdir, 'snapshot.pdf'))
|
62
|
+
end
|
Binary file
|
Binary file
|
@@ -0,0 +1,15 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfUtils::Color do
|
4
|
+
it "should convert to pdf color" do
|
5
|
+
PdfUtils::Color.new(255, 255, 0).to_pdf.should eql([1.0, 1.0, 0.0])
|
6
|
+
end
|
7
|
+
|
8
|
+
it "should convert to hex color" do
|
9
|
+
PdfUtils::Color.new(0, 1.0, 0).to_hex.should eql('00ff00')
|
10
|
+
end
|
11
|
+
|
12
|
+
it "should convert to rgb values" do
|
13
|
+
PdfUtils::Color.new('ff0000').to_rgb.should eql([255, 0, 0])
|
14
|
+
end
|
15
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfUtils::Info do
|
4
|
+
it "should extract meta information from the pdf" do
|
5
|
+
@info = PdfUtils::Info.new(fixture_file_path('marketing.pdf'))
|
6
|
+
|
7
|
+
@info.tagged .should eql(false)
|
8
|
+
@info.keywords .should eql("")
|
9
|
+
@info.page_size .should eql([595.0, 842.0])
|
10
|
+
@info.producer .should eql("Mac OS X 10.5.6 Quartz PDFContext")
|
11
|
+
@info.optimized .should eql(false)
|
12
|
+
@info.title .should eql("marketing")
|
13
|
+
@info.mod_date .should eql(Time.parse('2010/01/12 17:34:51 +0100'))
|
14
|
+
@info.creator .should eql("Preview")
|
15
|
+
@info.file_size .should eql(33179)
|
16
|
+
@info.pdf_version .should eql("1.4")
|
17
|
+
@info.creation_date .should eql(Time.parse('2009/02/04 13:42:55 +0100'))
|
18
|
+
@info.encrypted .should eql(false)
|
19
|
+
@info.author .should eql("Alexander Lang")
|
20
|
+
@info.page_format .should eql("A4")
|
21
|
+
@info.pages .should eql(3)
|
22
|
+
@info.subject .should eql("")
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,129 @@
|
|
1
|
+
require 'spec_helper'
|
2
|
+
|
3
|
+
describe PdfUtils do
|
4
|
+
|
5
|
+
describe "toc" do
|
6
|
+
|
7
|
+
it "should return an array of toc entries" do
|
8
|
+
PdfUtils.should_receive(:run_command).with(:pdftk, "stub.pdf dump_data").and_return(
|
9
|
+
"BookmarkTitle: Content\nBookmarkLevel: 1\nBookmarkPageNumber: 3\nBookmarkTitle: Intro\nBookmarkLevel: 2\nBookmarkPageNumber: 4")
|
10
|
+
PdfUtils::toc('stub.pdf').should eql([["Content",1,3], ["Intro",2,4]])
|
11
|
+
end
|
12
|
+
|
13
|
+
it "should not add an toc entry with page number < 1" do
|
14
|
+
PdfUtils.stub(:run_command => "BookmarkTitle: Content\nBookmarkLevel: 1\nBookmarkPageNumber: 0")
|
15
|
+
PdfUtils::toc('stub.pdf').should be_empty
|
16
|
+
end
|
17
|
+
|
18
|
+
it "should be empty if the document has no toc data" do
|
19
|
+
PdfUtils.should_receive(:run_command).with(:pdftk, "stub.pdf dump_data").and_return(
|
20
|
+
"InfoKey: Creator\nInfoValue: The Pragmatic Bookshelf")
|
21
|
+
PdfUtils::toc('stub.pdf').entries.should be_empty
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe "slice" do
|
26
|
+
|
27
|
+
it "should slice into a new pdf" do
|
28
|
+
sliced_path = Tempfile.new('sliced').path
|
29
|
+
PdfUtils::slice(fixture_file_path('marketing.pdf'), 2, 3, sliced_path)
|
30
|
+
PdfUtils::info(sliced_path).pages.should eql(2)
|
31
|
+
end
|
32
|
+
|
33
|
+
it "should slice the given file" do
|
34
|
+
sliced_path = duplicate_fixture_file('marketing.pdf').path
|
35
|
+
PdfUtils::slice!(sliced_path, 2, 3)
|
36
|
+
PdfUtils::info(sliced_path).pages.should eql(2)
|
37
|
+
end
|
38
|
+
|
39
|
+
it "should raise an error if pdftk fails to slice the pdf" do
|
40
|
+
lambda {
|
41
|
+
PdfUtils::slice('does/not/exist.pdf', 2, 3, 'does/not/exist/either.pdf')
|
42
|
+
}.should raise_error(RuntimeError)
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
describe "watermark" do
|
47
|
+
|
48
|
+
before :each do
|
49
|
+
@pdf_path = fixture_file_path('marketing.pdf')
|
50
|
+
end
|
51
|
+
|
52
|
+
it "should watermark into a new pdf" do
|
53
|
+
watermarked_path = Tempfile.new('watermarked').path
|
54
|
+
PdfUtils::watermark(@pdf_path, watermarked_path) do |pdf|
|
55
|
+
pdf.text "WATERMARKED PDF", :align => :center, :size => 8
|
56
|
+
end
|
57
|
+
pdf_text = PdfUtils::to_text(watermarked_path)
|
58
|
+
pdf_text.should include('WATERMARKED PDF')
|
59
|
+
pdf_text.should include('Beltz Verlag Weinheim')
|
60
|
+
end
|
61
|
+
|
62
|
+
it "should watermark the given file" do
|
63
|
+
watermarked_path = duplicate_fixture_file('marketing.pdf').path
|
64
|
+
PdfUtils::watermark!(watermarked_path) do |pdf|
|
65
|
+
pdf.text "WATERMARKED PDF", :align => :center, :size => 8
|
66
|
+
end
|
67
|
+
pdf_text = PdfUtils::to_text(watermarked_path)
|
68
|
+
pdf_text.should include('WATERMARKED PDF')
|
69
|
+
pdf_text.should include('Beltz Verlag Weinheim')
|
70
|
+
end
|
71
|
+
|
72
|
+
it "should pass options to the watermark pdf" do
|
73
|
+
Prawn::Document.should_receive(:generate).with(anything, :page_size => [25, 25])
|
74
|
+
PdfUtils::watermark(@pdf_path, Tempfile.new('target').path, :page_size => [25, 25]) {}
|
75
|
+
end
|
76
|
+
end
|
77
|
+
|
78
|
+
describe "annotate" do
|
79
|
+
|
80
|
+
before :each do
|
81
|
+
@pdf_path = fixture_file_path('page.pdf')
|
82
|
+
@annotations = [{
|
83
|
+
:Type => :Annot,
|
84
|
+
:Subtype => :Text,
|
85
|
+
:Name => :Comment,
|
86
|
+
:Rect => [10, 10, 34, 34],
|
87
|
+
:Contents => 'Dies ist eine Notiz.',
|
88
|
+
:C => PdfUtils::Color.new('fdaa00').to_pdf,
|
89
|
+
:M => Time.now,
|
90
|
+
:F => 4
|
91
|
+
}]
|
92
|
+
end
|
93
|
+
|
94
|
+
it "should annotate into a new pdf" do
|
95
|
+
annotated_path = Tempfile.new('annotated').path
|
96
|
+
PdfUtils::annotate(@pdf_path, @annotations, annotated_path)
|
97
|
+
annotations = PdfUtils::annotations(annotated_path)
|
98
|
+
annotations.should have(1).item
|
99
|
+
annotations.first[:Contents].should eql('Dies ist eine Notiz.')
|
100
|
+
end
|
101
|
+
end
|
102
|
+
|
103
|
+
describe "thumbnail" do
|
104
|
+
|
105
|
+
it "should create a thumbnail of the given page" do
|
106
|
+
source = fixture_file_path('marketing.pdf')
|
107
|
+
target = File.join(Dir.tmpdir, 'marketing.png')
|
108
|
+
FileUtils.rm(target) if File.exists?(target)
|
109
|
+
PdfUtils::thumbnail(source, :page => '3', :target => target)
|
110
|
+
File.should be_exists(target)
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
describe "snapshot" do
|
115
|
+
|
116
|
+
it "should rasterize the given page" do
|
117
|
+
path = duplicate_fixture_file('marketing.pdf').path
|
118
|
+
original_info = PdfUtils::info(path)
|
119
|
+
|
120
|
+
PdfUtils::snapshot!(path, :page => 2)
|
121
|
+
|
122
|
+
info = PdfUtils::info(path)
|
123
|
+
info.pages.should eql(1)
|
124
|
+
info.page_width. should be_close(original_info.page_width , 1.0)
|
125
|
+
info.page_height.should be_close(original_info.page_height, 1.0)
|
126
|
+
info.page_format.should eql(original_info.page_format)
|
127
|
+
end
|
128
|
+
end
|
129
|
+
end
|
data/spec/spec_helper.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require "rubygems"
|
2
|
+
require 'test/unit'
|
3
|
+
require "spec"
|
4
|
+
require 'tempfile'
|
5
|
+
|
6
|
+
require 'pdf_utils'
|
7
|
+
|
8
|
+
def fixture_file_path(file)
|
9
|
+
File.join(File.dirname(__FILE__), 'fixtures', file)
|
10
|
+
end
|
11
|
+
|
12
|
+
def fixture_file(file)
|
13
|
+
File.open(fixture_file_path(file))
|
14
|
+
end
|
15
|
+
|
16
|
+
def duplicate_fixture_file(file)
|
17
|
+
tempfile = Tempfile.new(File.basename(file))
|
18
|
+
FileUtils.cp_r(fixture_file_path(file), tempfile.path)
|
19
|
+
tempfile
|
20
|
+
end
|
metadata
ADDED
@@ -0,0 +1,78 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdf_utils
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
prerelease: false
|
5
|
+
segments:
|
6
|
+
- 0
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
version: 0.1.0
|
10
|
+
platform: ruby
|
11
|
+
authors:
|
12
|
+
- Lukas Rieder
|
13
|
+
- Andreas Korth
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-06-03 00:00:00 +02:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: " Requires xpdf, pdftk, swftools/pdf2swf and imagemagick.\n You can check their functionality by running `$ rake check_system_dependencies\xC2\xB4.\n"
|
23
|
+
email: l.rieder@gmail.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files: []
|
29
|
+
|
30
|
+
files:
|
31
|
+
- Rakefile
|
32
|
+
- VERSION
|
33
|
+
- lib/in_tempdir.rb
|
34
|
+
- lib/pdf_utils.rb
|
35
|
+
- lib/pdf_utils/color.rb
|
36
|
+
- lib/pdf_utils/info.rb
|
37
|
+
- script/check_system_dependencies
|
38
|
+
- spec/fixtures/marketing.pdf
|
39
|
+
- spec/fixtures/page.pdf
|
40
|
+
- spec/pdf_utils/color_spec.rb
|
41
|
+
- spec/pdf_utils/info_spec.rb
|
42
|
+
- spec/pdf_utils_spec.rb
|
43
|
+
- spec/spec_helper.rb
|
44
|
+
has_rdoc: true
|
45
|
+
homepage: http://github.com/Overbryd/pdf_utils
|
46
|
+
licenses: []
|
47
|
+
|
48
|
+
post_install_message:
|
49
|
+
rdoc_options:
|
50
|
+
- --charset=UTF-8
|
51
|
+
require_paths:
|
52
|
+
- lib
|
53
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
54
|
+
requirements:
|
55
|
+
- - ">="
|
56
|
+
- !ruby/object:Gem::Version
|
57
|
+
segments:
|
58
|
+
- 0
|
59
|
+
version: "0"
|
60
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
61
|
+
requirements:
|
62
|
+
- - ">="
|
63
|
+
- !ruby/object:Gem::Version
|
64
|
+
segments:
|
65
|
+
- 0
|
66
|
+
version: "0"
|
67
|
+
requirements: []
|
68
|
+
|
69
|
+
rubyforge_project:
|
70
|
+
rubygems_version: 1.3.6
|
71
|
+
signing_key:
|
72
|
+
specification_version: 3
|
73
|
+
summary: PdfUtils abstracts a lot of well working UNIX tools for PDF files
|
74
|
+
test_files:
|
75
|
+
- spec/pdf_utils/color_spec.rb
|
76
|
+
- spec/pdf_utils/info_spec.rb
|
77
|
+
- spec/pdf_utils_spec.rb
|
78
|
+
- spec/spec_helper.rb
|