pdf_utils 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|