pdfmult 1.0.0
Sign up to get free protection for your applications and to get access to all the features.
- data/README.md +83 -0
- data/Rakefile +64 -0
- data/bin/pdfmult +5 -0
- data/example1.fig +21 -0
- data/example1.png +0 -0
- data/example2.fig +46 -0
- data/example2.png +0 -0
- data/lib/pdfmult.rb +335 -0
- data/man/pdfmult.1 +49 -0
- data/pdfmult.gemspec +42 -0
- data/pdfmult.h2m +8 -0
- data/test/sample.pdf +0 -0
- data/test/sample.tex +37 -0
- data/test/test_pdfmult.rb +99 -0
- metadata +105 -0
data/README.md
ADDED
@@ -0,0 +1,83 @@
|
|
1
|
+
pdfmult
|
2
|
+
=======
|
3
|
+
|
4
|
+
`pdfmult` is a command line tool (written in [Ruby][Ruby]) that
|
5
|
+
rearranges multiple copies of a PDF page (shrunken) on one page.
|
6
|
+
|
7
|
+
The paper size of the produced PDF file is A4,
|
8
|
+
the input file is also assumed to be in A4 format.
|
9
|
+
The input PDF file may consist of several pages.
|
10
|
+
If `pdfmult` succeeds in obtaining the page count it will rearrange all pages,
|
11
|
+
if not, only the first page is processed
|
12
|
+
(unless the page count was specified via command line option).
|
13
|
+
|
14
|
+
Examples
|
15
|
+
--------
|
16
|
+
|
17
|
+
Use the program as shown in the examples below.
|
18
|
+
|
19
|
+
* `pdfmult sample.pdf`
|
20
|
+
|
21
|
+
writes 2 copies of `sample.pdf` to `sample_2.pdf`
|
22
|
+
|
23
|
+
<img src="/stomar/pdfmult/raw/master/example1.png" alt="" width="152" height="59">
|
24
|
+
|
25
|
+
* `pdfmult -n 4 sample.pdf`
|
26
|
+
|
27
|
+
writes 4 copies of `sample.pdf` to `sample_4.pdf`
|
28
|
+
|
29
|
+
<img src="/stomar/pdfmult/raw/master/example2.png" alt="" width="234" height="59">
|
30
|
+
|
31
|
+
* `pdfmult sample.pdf -o outfile.pdf`
|
32
|
+
|
33
|
+
writes 2 copies of `sample.pdf` to `outfile.pdf`
|
34
|
+
|
35
|
+
* `pdfmult sample.pdf -p 3`
|
36
|
+
|
37
|
+
processes the first 3 pages of `sample.pdf`
|
38
|
+
|
39
|
+
Installation
|
40
|
+
------------
|
41
|
+
|
42
|
+
Use `gem install pdfmult`.
|
43
|
+
|
44
|
+
Or opy `lib/pdfmult.rb` under the name `pdfmult` into your search path.
|
45
|
+
|
46
|
+
On a Linux system you can use `[sudo] rake install`
|
47
|
+
to install `pdfmult` and its man page to `/usr/local`.
|
48
|
+
|
49
|
+
Requirements
|
50
|
+
------------
|
51
|
+
|
52
|
+
As of now, `pdfmult` has only been tested on a Linux system.
|
53
|
+
|
54
|
+
- `pdfmult` is written in [Ruby][Ruby], so Ruby must be installed on your system.
|
55
|
+
- `pdfmult` uses `pdflatex` with the `pdfpages` package, so both have to be installed on the system.
|
56
|
+
- `pdfmult` tries to obtain the page count of PDF files with `pdfinfo`.
|
57
|
+
If it fails, by default only the first page of a PDF file will be processed.
|
58
|
+
|
59
|
+
Documentation
|
60
|
+
-------------
|
61
|
+
|
62
|
+
`pdfmult --help` prints a brief help message.
|
63
|
+
|
64
|
+
If you installed `pdfmult` using `rake install` you can read
|
65
|
+
its man page with `man pdfmult`.
|
66
|
+
|
67
|
+
Reporting bugs
|
68
|
+
--------------
|
69
|
+
|
70
|
+
Report bugs on the `pdfmult` home page: <https://github.com/stomar/pdfmult/>
|
71
|
+
|
72
|
+
License
|
73
|
+
-------
|
74
|
+
|
75
|
+
Copyright © 2011-2012, Marcus Stollsteimer
|
76
|
+
|
77
|
+
`pdfmult` is free software: you can redistribute it and/or modify
|
78
|
+
it under the terms of the GNU General Public License version 3 or later (GPLv3+),
|
79
|
+
see [www.gnu.org/licenses/gpl.html](http://www.gnu.org/licenses/gpl.html).
|
80
|
+
There is NO WARRANTY, to the extent permitted by law.
|
81
|
+
|
82
|
+
|
83
|
+
[Ruby]: http://www.ruby-lang.org/
|
data/Rakefile
ADDED
@@ -0,0 +1,64 @@
|
|
1
|
+
# rakefile for the pdfmult script.
|
2
|
+
#
|
3
|
+
# Copyright (C) 2012 Marcus Stollsteimer
|
4
|
+
|
5
|
+
require 'rake/testtask'
|
6
|
+
|
7
|
+
BINDIR = '/usr/local/bin'
|
8
|
+
MANDIR = '/usr/local/man/man1'
|
9
|
+
|
10
|
+
HELP2MAN = 'help2man'
|
11
|
+
SED = 'sed'
|
12
|
+
|
13
|
+
BINARY = 'lib/pdfmult.rb'
|
14
|
+
BINARYNAME = 'pdfmult' # install using this name
|
15
|
+
MANPAGE = 'man/pdfmult.1'
|
16
|
+
H2MFILE = 'pdfmult.h2m'
|
17
|
+
|
18
|
+
|
19
|
+
def gemspec_file
|
20
|
+
'pdfmult.gemspec'
|
21
|
+
end
|
22
|
+
|
23
|
+
|
24
|
+
task :default => [:test]
|
25
|
+
|
26
|
+
Rake::TestTask.new do |t|
|
27
|
+
t.pattern = 'test/**/test_*.rb'
|
28
|
+
t.ruby_opts << '-rubygems'
|
29
|
+
t.verbose = true
|
30
|
+
t.warning = true
|
31
|
+
end
|
32
|
+
|
33
|
+
|
34
|
+
desc 'Install binary and man page'
|
35
|
+
task :install => [BINARY, MANPAGE] do
|
36
|
+
mkdir_p BINDIR
|
37
|
+
install(BINARY, BINDIR + '/' + BINARYNAME)
|
38
|
+
mkdir_p MANDIR
|
39
|
+
install(MANPAGE, MANDIR, :mode => 0644)
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
desc 'Uninstall binary and man page'
|
44
|
+
task :uninstall do
|
45
|
+
rm "#{BINDIR}/#{BINARYNAME}"
|
46
|
+
manfile = File.basename(MANPAGE)
|
47
|
+
rm "#{MANDIR}/#{manfile}"
|
48
|
+
end
|
49
|
+
|
50
|
+
|
51
|
+
desc 'Create man page'
|
52
|
+
task :man => [MANPAGE]
|
53
|
+
|
54
|
+
file MANPAGE => [BINARY, H2MFILE] do
|
55
|
+
sh "#{HELP2MAN} --no-info --include=#{H2MFILE} -o #{MANPAGE} ./#{BINARY}"
|
56
|
+
sh "#{SED} -i '/\.PP/{N;s/\.PP\\nOptions/.SH OPTIONS/}' #{MANPAGE}"
|
57
|
+
sh "#{SED} -i 's/^License GPL/.br\\nLicense GPL/;s/There is NO WARRANTY/.br\\nThere is NO WARRANTY/' #{MANPAGE}"
|
58
|
+
end
|
59
|
+
|
60
|
+
|
61
|
+
desc 'Build gem'
|
62
|
+
task :build do
|
63
|
+
sh "gem build #{gemspec_file}"
|
64
|
+
end
|
data/bin/pdfmult
ADDED
data/example1.fig
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
#FIG 3.2 Produced by xfig version 3.2.5b
|
2
|
+
Landscape
|
3
|
+
Center
|
4
|
+
Metric
|
5
|
+
A4
|
6
|
+
100.00
|
7
|
+
Single
|
8
|
+
-2
|
9
|
+
1200 2
|
10
|
+
2 1 0 4 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
11
|
+
1 1 2.00 120.00 180.00
|
12
|
+
1395 450 1845 450
|
13
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
14
|
+
540 0 1215 0 1215 900 540 900 540 0
|
15
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
16
|
+
2025 90 2925 90 2925 765 2025 765 2025 90
|
17
|
+
2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
18
|
+
2475 90 2475 765
|
19
|
+
4 1 0 50 -1 16 32 0.0000 4 405 375 855 630 A\001
|
20
|
+
4 1 0 50 -1 16 24 0.0000 4 315 270 2700 585 A\001
|
21
|
+
4 1 0 50 -1 16 24 0.0000 4 315 270 2250 585 A\001
|
data/example1.png
ADDED
Binary file
|
data/example2.fig
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
#FIG 3.2 Produced by xfig version 3.2.5b
|
2
|
+
Landscape
|
3
|
+
Center
|
4
|
+
Metric
|
5
|
+
A4
|
6
|
+
100.00
|
7
|
+
Single
|
8
|
+
-2
|
9
|
+
1200 2
|
10
|
+
6 450 0 1125 900
|
11
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
12
|
+
450 0 1125 0 1125 900 450 900 450 0
|
13
|
+
4 1 0 50 -1 16 32 0.0000 4 390 285 765 630 2\001
|
14
|
+
-6
|
15
|
+
6 1935 0 2610 900
|
16
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
17
|
+
1935 0 2610 0 2610 900 1935 900 1935 0
|
18
|
+
2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
19
|
+
1935 450 2610 450
|
20
|
+
2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
21
|
+
2272 0 2272 900
|
22
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2430 315 1\001
|
23
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2115 765 1\001
|
24
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2430 765 1\001
|
25
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2115 315 1\001
|
26
|
+
-6
|
27
|
+
6 -315 0 360 900
|
28
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
29
|
+
-315 0 360 0 360 900 -315 900 -315 0
|
30
|
+
4 1 0 50 -1 16 32 0.0000 4 390 285 0 630 1\001
|
31
|
+
-6
|
32
|
+
6 2700 0 3375 900
|
33
|
+
2 2 0 1 0 7 50 -1 -1 0.000 0 0 -1 0 0 5
|
34
|
+
2700 0 3375 0 3375 900 2700 900 2700 0
|
35
|
+
2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
36
|
+
2700 450 3375 450
|
37
|
+
2 1 2 1 0 7 50 -1 -1 3.000 0 0 -1 0 0 2
|
38
|
+
3037 0 3037 900
|
39
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 3195 315 2\001
|
40
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2880 765 2\001
|
41
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 3195 765 2\001
|
42
|
+
4 1 0 50 -1 16 16 0.0000 4 195 150 2880 315 2\001
|
43
|
+
-6
|
44
|
+
2 1 0 4 0 7 50 -1 -1 0.000 0 0 -1 1 0 2
|
45
|
+
1 1 2.00 120.00 180.00
|
46
|
+
1305 450 1755 450
|
data/example2.png
ADDED
Binary file
|
data/lib/pdfmult.rb
ADDED
@@ -0,0 +1,335 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# == Name
|
3
|
+
#
|
4
|
+
# pdfmult - put multiple copies of a PDF page on one page
|
5
|
+
#
|
6
|
+
# == Synopsis
|
7
|
+
#
|
8
|
+
# pdfmult [options] file
|
9
|
+
#
|
10
|
+
# == Description
|
11
|
+
#
|
12
|
+
# +pdfmult+ rearranges multiple copies of a PDF page (shrunken) on one page.
|
13
|
+
#
|
14
|
+
# The paper size of the produced PDF file is A4,
|
15
|
+
# the input file is also assumed to be in A4 format.
|
16
|
+
# The input PDF file may consist of several pages.
|
17
|
+
# If +pdfmult+ succeeds in obtaining the page count it will rearrange all pages,
|
18
|
+
# if not, only the first page is processed
|
19
|
+
# (unless the page count was specified via command line option).
|
20
|
+
#
|
21
|
+
# +pdfmult+ uses +pdflatex+ with the +pdfpages+ package,
|
22
|
+
# so both have to be installed on the system.
|
23
|
+
#
|
24
|
+
# == Options
|
25
|
+
#
|
26
|
+
# -n, --number:: Number of copies to put on one page: 2 (default), 4, 8, 9, 16.
|
27
|
+
#
|
28
|
+
# -o, --output:: Output file (default: infile_NUMBER.pdf).
|
29
|
+
#
|
30
|
+
# -p, --pages:: Number of pages to convert.
|
31
|
+
# If given, +pdfmult+ does not try to obtain the page count from the source PDF.
|
32
|
+
#
|
33
|
+
# -h, --help:: Prints a brief help message and exits.
|
34
|
+
#
|
35
|
+
# -v, --version:: Prints a brief version information and exits.
|
36
|
+
#
|
37
|
+
# == Examples
|
38
|
+
#
|
39
|
+
# pdfmult sample.pdf # => sample_2.pdf (2 copies)
|
40
|
+
# pdfmult -n 4 sample.pdf # => sample_4.pdf (4 copies)
|
41
|
+
# pdfmult sample.pdf -o outfile.pdf # => outfile.pdf (2 copies)
|
42
|
+
# pdfmult sample.pdf -p 3 # => processes 3 pages
|
43
|
+
#
|
44
|
+
# == Author
|
45
|
+
#
|
46
|
+
# Copyright (C) 2011-2012 Marcus Stollsteimer
|
47
|
+
#
|
48
|
+
# License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
49
|
+
#
|
50
|
+
|
51
|
+
|
52
|
+
require 'optparse'
|
53
|
+
require 'tempfile'
|
54
|
+
require 'fileutils'
|
55
|
+
|
56
|
+
# This module contains the classes for the +pdfmult+ tool
|
57
|
+
module Pdfmult
|
58
|
+
|
59
|
+
PROGNAME = 'pdfmult'
|
60
|
+
VERSION = '1.0.0'
|
61
|
+
DATE = '2012-03-15'
|
62
|
+
COPYRIGHT = "Copyright (C) 2011-2012 Marcus Stollsteimer.\n" +
|
63
|
+
"License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>\n" +
|
64
|
+
"This is free software: you are free to change and redistribute it.\n" +
|
65
|
+
"There is NO WARRANTY, to the extent permitted by law."
|
66
|
+
|
67
|
+
PDFLATEX = '/usr/bin/pdflatex'
|
68
|
+
KPSEWHICH = '/usr/bin/kpsewhich'
|
69
|
+
|
70
|
+
# Parser for the command line options.
|
71
|
+
# The class method parse! does the job.
|
72
|
+
class Optionparser
|
73
|
+
|
74
|
+
# Parses the command line options from +argv+.
|
75
|
+
# (+argv+ is cleared).
|
76
|
+
# Might print out help or version information.
|
77
|
+
#
|
78
|
+
# +argv+ - array with the command line options
|
79
|
+
#
|
80
|
+
# Returns a hash containing the option parameters.
|
81
|
+
def self.parse!(argv)
|
82
|
+
|
83
|
+
options = {
|
84
|
+
:number => 2,
|
85
|
+
:infile => nil,
|
86
|
+
:outfile => nil,
|
87
|
+
:pages => nil
|
88
|
+
}
|
89
|
+
|
90
|
+
opt_parser = OptionParser.new do |opt|
|
91
|
+
opt.banner = "Usage: #{PROGNAME} [options] file"
|
92
|
+
opt.separator ''
|
93
|
+
opt.separator 'pdfmult is a command line tool that'
|
94
|
+
opt.separator 'rearranges multiple copies of a PDF page (shrunken) on one page.'
|
95
|
+
opt.separator ''
|
96
|
+
opt.separator 'The paper size of the produced PDF file is A4,'
|
97
|
+
opt.separator 'the input file is also assumed to be in A4 format.'
|
98
|
+
opt.separator 'The input PDF file may consist of several pages.'
|
99
|
+
opt.separator 'If pdfmult succeeds in obtaining the page count it will rearrange all pages,'
|
100
|
+
opt.separator 'if not, only the first page is processed'
|
101
|
+
opt.separator '(unless the page count was specified via command line option).'
|
102
|
+
opt.separator ''
|
103
|
+
opt.separator 'Options'
|
104
|
+
opt.separator ''
|
105
|
+
|
106
|
+
# process --version and --help first,
|
107
|
+
# exit successfully (GNU Coding Standards)
|
108
|
+
opt.on_tail('-h', '--help', 'Prints a brief help message and exits.') do
|
109
|
+
puts opt_parser
|
110
|
+
puts "\nReport bugs on the pdfmult home page: <https://github.com/stomar/pdfmult/>"
|
111
|
+
exit
|
112
|
+
end
|
113
|
+
|
114
|
+
opt.on_tail('-v', '--version',
|
115
|
+
'Prints a brief version information and exits.') do
|
116
|
+
puts "#{PROGNAME} #{VERSION}"
|
117
|
+
puts COPYRIGHT
|
118
|
+
exit
|
119
|
+
end
|
120
|
+
|
121
|
+
opt.on('-n', '--number NUMBER', ['2', '4', '8', '9', '16'], Integer,
|
122
|
+
'Number of copies to put on one page: 2 (default), 4, 8, 9, 16.') do |n|
|
123
|
+
options[:number] = n
|
124
|
+
end
|
125
|
+
|
126
|
+
opt.on('-o', '--output FILE', String,
|
127
|
+
'Output file (default: file_2.pdf).') do |f|
|
128
|
+
options[:outfile] = f
|
129
|
+
end
|
130
|
+
|
131
|
+
opt.on('-p', '--pages NUMBER', Integer,
|
132
|
+
'Number of pages to convert.',
|
133
|
+
"If given, #{PROGNAME} does not try to obtain the page count from the source PDF.") do |p|
|
134
|
+
raise(OptionParser::InvalidArgument, p) unless p > 0
|
135
|
+
options[:pages] = p
|
136
|
+
end
|
137
|
+
|
138
|
+
opt.separator ''
|
139
|
+
end
|
140
|
+
opt_parser.parse!(argv)
|
141
|
+
|
142
|
+
# only input file should be left in argv
|
143
|
+
raise(ArgumentError, 'wrong number of arguments') if (argv.size != 1 || argv[0] == '')
|
144
|
+
|
145
|
+
options[:infile] = argv.pop
|
146
|
+
|
147
|
+
# set output file unless set by option
|
148
|
+
options[:outfile] ||= options[:infile].gsub(/(.pdf)$/, '') + "_#{options[:number].to_s}.pdf"
|
149
|
+
|
150
|
+
options
|
151
|
+
end
|
152
|
+
end
|
153
|
+
|
154
|
+
# Class for the LaTeX document.
|
155
|
+
#
|
156
|
+
# Create an instance with LaTeXDocument.new, specifying
|
157
|
+
# the input file, the number of pages to put on one page,
|
158
|
+
# and the page count of the input file.
|
159
|
+
#
|
160
|
+
# The method +to_s+ returns the document as multiline string.
|
161
|
+
class LaTeXDocument
|
162
|
+
|
163
|
+
attr_accessor :infile, :number, :page_count
|
164
|
+
|
165
|
+
HEADER =
|
166
|
+
"\\documentclass[CLASSOPTIONS]{article}\n" +
|
167
|
+
"\\usepackage{pdfpages}\n" +
|
168
|
+
"\\pagestyle{empty}\n" +
|
169
|
+
"\\setlength{\\parindent}{0pt}\n" +
|
170
|
+
"\\begin{document}%\n"
|
171
|
+
|
172
|
+
CONTENT =
|
173
|
+
"\\includepdf[pages={PAGES},nup=GEOMETRY]{FILENAME}%\n"
|
174
|
+
|
175
|
+
FOOTER =
|
176
|
+
'\end{document}'
|
177
|
+
|
178
|
+
# Initializes a LaTeXDocument instance.
|
179
|
+
#
|
180
|
+
# +infile+ - input file name
|
181
|
+
# +number+ - number of pages to put on one page
|
182
|
+
# +page_count+ - page count of the input file
|
183
|
+
def initialize(infile, number, page_count)
|
184
|
+
@infile = infile
|
185
|
+
@number = number
|
186
|
+
@page_count = page_count
|
187
|
+
end
|
188
|
+
|
189
|
+
def to_s
|
190
|
+
class_options = 'a4paper'
|
191
|
+
page_string = 'PAGE,' * (@number - 1) + 'PAGE' # 4 copies: e.g. 1,1,1,1
|
192
|
+
|
193
|
+
case @number
|
194
|
+
when 2
|
195
|
+
class_options += ',landscape'
|
196
|
+
geometry = '2x1'
|
197
|
+
when 4
|
198
|
+
geometry = '2x2'
|
199
|
+
when 8
|
200
|
+
class_options += ',landscape'
|
201
|
+
geometry = '4x2'
|
202
|
+
when 9
|
203
|
+
geometry = '3x3'
|
204
|
+
when 16
|
205
|
+
geometry = '4x4'
|
206
|
+
end
|
207
|
+
|
208
|
+
content_template = CONTENT.gsub(/PAGES/, page_string).gsub(/GEOMETRY/, geometry).gsub(/FILENAME/, @infile)
|
209
|
+
|
210
|
+
content = HEADER.gsub(/CLASSOPTIONS/, class_options)
|
211
|
+
@page_count.times do |i|
|
212
|
+
content << content_template.gsub(/PAGE/,"#{i+1}")
|
213
|
+
end
|
214
|
+
|
215
|
+
content << FOOTER
|
216
|
+
end
|
217
|
+
end
|
218
|
+
|
219
|
+
# A class for PDF meta data (up to now only used for the page count).
|
220
|
+
#
|
221
|
+
# Create an instance with PDFInfo.new, specifying the file name.
|
222
|
+
# +PDFInfo+ tries to use the +pdfinfo+ system tool to obtain meta data.
|
223
|
+
# If successful, the attribute +page_count+ contains the page count,
|
224
|
+
# else the attribute is set to +nil+.
|
225
|
+
class PDFInfo
|
226
|
+
|
227
|
+
PDFINFOCMD = '/usr/bin/pdfinfo'
|
228
|
+
|
229
|
+
# Contains the page count of the input file, or nil.
|
230
|
+
attr_reader :page_count
|
231
|
+
|
232
|
+
# This is the initialization method for the class.
|
233
|
+
#
|
234
|
+
# +file+ - file name of the PDF file
|
235
|
+
def initialize(file, options={})
|
236
|
+
@page_count = nil
|
237
|
+
infos = Hash.new
|
238
|
+
|
239
|
+
binary = options[:pdfinfocmd] || PDFINFOCMD # only for unit tests
|
240
|
+
command = "#{binary} #{file}"
|
241
|
+
if Application.command_available?(command)
|
242
|
+
infostring = `#{command}`
|
243
|
+
infostring.each_line do |line|
|
244
|
+
key, val = line.chomp.split(/\s*:\s*/, 2)
|
245
|
+
infos[key] = val
|
246
|
+
end
|
247
|
+
value = infos['Pages']
|
248
|
+
@page_count = value.to_i unless value.nil?
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
# Returns true if default +pdfinfo+ system tool is available (for unit tests).
|
253
|
+
def self.infocmd_available? # :nodoc:
|
254
|
+
Application.command_available?(PDFINFOCMD + ' -v')
|
255
|
+
end
|
256
|
+
end
|
257
|
+
|
258
|
+
# The main program. It's run! method is called
|
259
|
+
# if the script is run from the command line.
|
260
|
+
# It parses the command line arguments and does the job.
|
261
|
+
class Application
|
262
|
+
|
263
|
+
ERRORCODE = {:general => 1, :usage => 2}
|
264
|
+
|
265
|
+
# The main program.
|
266
|
+
def self.run!
|
267
|
+
|
268
|
+
# parse options
|
269
|
+
begin
|
270
|
+
options = Optionparser.parse!(ARGV)
|
271
|
+
rescue => e
|
272
|
+
usage_fail(e.message)
|
273
|
+
end
|
274
|
+
|
275
|
+
# tests
|
276
|
+
general_fail("`#{PDFLATEX}' seems not to be installed") unless command_available?("#{PDFLATEX} --version")
|
277
|
+
general_fail("`pdfpages.sty' seems not to be installed") unless command_available?("#{KPSEWHICH} pdfpages.sty")
|
278
|
+
|
279
|
+
# main body #
|
280
|
+
|
281
|
+
infile = options[:infile]
|
282
|
+
outfile = options[:outfile]
|
283
|
+
|
284
|
+
# test input file
|
285
|
+
usage_fail("no such file: `#{infile}'") unless File.exist?(infile)
|
286
|
+
usage_fail("specified input not of the type `file'") unless File.ftype(infile) == 'file'
|
287
|
+
|
288
|
+
# set page number (get PDF info if necessary)
|
289
|
+
pages = options[:pages]
|
290
|
+
pages ||= PDFInfo.new(infile).page_count
|
291
|
+
pages ||= 1
|
292
|
+
|
293
|
+
# create LaTeX document
|
294
|
+
document = LaTeXDocument.new(infile, options[:number], pages)
|
295
|
+
|
296
|
+
Dir.mktmpdir('pdfmult') do |dir|
|
297
|
+
open("#{dir}/pdfmult.tex", 'w') do |f|
|
298
|
+
pdfpath = "#{dir}/pdfmult.pdf"
|
299
|
+
f.write(document.to_s)
|
300
|
+
f.flush
|
301
|
+
system("/usr/bin/pdflatex -output-directory #{dir} pdfmult.tex")
|
302
|
+
puts "Writing on #{outfile}."
|
303
|
+
FileUtils::mv(pdfpath, outfile)
|
304
|
+
end
|
305
|
+
end
|
306
|
+
end
|
307
|
+
|
308
|
+
# Prints an error message and exits.
|
309
|
+
def self.general_fail(message) # :nodoc:
|
310
|
+
warn "#{PROGNAME}: #{message}"
|
311
|
+
exit ERRORCODE[:general]
|
312
|
+
end
|
313
|
+
|
314
|
+
# Prints an error message and a short help information, then exits.
|
315
|
+
def self.usage_fail(message) # :nodoc:
|
316
|
+
warn "#{PROGNAME}: #{message}"
|
317
|
+
warn "Use `#{PROGNAME} --help' for valid options."
|
318
|
+
exit ERRORCODE[:usage]
|
319
|
+
end
|
320
|
+
|
321
|
+
# Tests silently whether the given system command is available.
|
322
|
+
#
|
323
|
+
# +command+ - command to test
|
324
|
+
def self.command_available?(command) # :nodoc:
|
325
|
+
!!system(command + ' >/dev/null 2>&1')
|
326
|
+
end
|
327
|
+
end
|
328
|
+
|
329
|
+
### call main method only if called on command line
|
330
|
+
|
331
|
+
if __FILE__ == $0
|
332
|
+
Application.run!
|
333
|
+
end
|
334
|
+
|
335
|
+
end # module
|
data/man/pdfmult.1
ADDED
@@ -0,0 +1,49 @@
|
|
1
|
+
.\" DO NOT MODIFY THIS FILE! It was generated by help2man 1.40.4.
|
2
|
+
.TH PDFMULT "1" "March 2012" "pdfmult 1.0.0" "User Commands"
|
3
|
+
.SH NAME
|
4
|
+
pdfmult \- puts multiple copies of a PDF page on one page
|
5
|
+
.SH SYNOPSIS
|
6
|
+
.B pdfmult
|
7
|
+
[\fIoptions\fR] \fIfile\fR
|
8
|
+
.SH DESCRIPTION
|
9
|
+
pdfmult is a command line tool that
|
10
|
+
rearranges multiple copies of a PDF page (shrunken) on one page.
|
11
|
+
.PP
|
12
|
+
The paper size of the produced PDF file is A4,
|
13
|
+
the input file is also assumed to be in A4 format.
|
14
|
+
The input PDF file may consist of several pages.
|
15
|
+
If pdfmult succeeds in obtaining the page count it will rearrange all pages,
|
16
|
+
if not, only the first page is processed
|
17
|
+
(unless the page count was specified via command line option).
|
18
|
+
.SH OPTIONS
|
19
|
+
.TP
|
20
|
+
\fB\-n\fR, \fB\-\-number\fR NUMBER
|
21
|
+
Number of copies to put on one page: 2 (default), 4, 8, 9, 16.
|
22
|
+
.TP
|
23
|
+
\fB\-o\fR, \fB\-\-output\fR FILE
|
24
|
+
Output file (default: file_2.pdf).
|
25
|
+
.TP
|
26
|
+
\fB\-p\fR, \fB\-\-pages\fR NUMBER
|
27
|
+
Number of pages to convert.
|
28
|
+
If given, pdfmult does not try to obtain the page count from the source PDF.
|
29
|
+
.TP
|
30
|
+
\fB\-h\fR, \fB\-\-help\fR
|
31
|
+
Prints a brief help message and exits.
|
32
|
+
.TP
|
33
|
+
\fB\-v\fR, \fB\-\-version\fR
|
34
|
+
Prints a brief version information and exits.
|
35
|
+
.SH EXAMPLES
|
36
|
+
pdfmult sample.pdf # => sample_2.pdf (2 copies)
|
37
|
+
pdfmult -n 4 sample.pdf # => sample_4.pdf (4 copies)
|
38
|
+
pdfmult sample.pdf -o outfile.pdf # => outfile.pdf (2 copies)
|
39
|
+
pdfmult sample.pdf -p 3 # => processes 3 pages
|
40
|
+
.SH "REPORTING BUGS"
|
41
|
+
Report bugs on the pdfmult home page: <https://github.com/stomar/pdfmult/>
|
42
|
+
.SH COPYRIGHT
|
43
|
+
Copyright \(co 2011\-2012 Marcus Stollsteimer.
|
44
|
+
.br
|
45
|
+
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html>
|
46
|
+
.br
|
47
|
+
This is free software: you are free to change and redistribute it.
|
48
|
+
.br
|
49
|
+
There is NO WARRANTY, to the extent permitted by law.
|
data/pdfmult.gemspec
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'lib/pdfmult'
|
2
|
+
|
3
|
+
version = Pdfmult::VERSION
|
4
|
+
date = Pdfmult::DATE
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = 'pdfmult'
|
8
|
+
s.version = version
|
9
|
+
s.date = date
|
10
|
+
s.rubyforge_project = 'pdfmult'
|
11
|
+
|
12
|
+
s.description = 'pdfmult is a command line tool that rearranges ' +
|
13
|
+
'multiple copies of a PDF page (shrunken) on one page.'
|
14
|
+
s.summary = 'pdfmult - puts multiple copies of a PDF page on one page'
|
15
|
+
|
16
|
+
s.authors = ['Marcus Stollsteimer']
|
17
|
+
s.email = 'sto.mar@web.de'
|
18
|
+
s.homepage = 'https://github.com/stomar/pdfmult/'
|
19
|
+
|
20
|
+
s.license = 'GPL-3'
|
21
|
+
|
22
|
+
s.requirements << 'pdflatex and the pdfpages package'
|
23
|
+
|
24
|
+
s.executables = ['pdfmult']
|
25
|
+
s.bindir = 'bin'
|
26
|
+
s.require_path = 'lib'
|
27
|
+
s.test_files = Dir.glob('test/**/test_*.rb')
|
28
|
+
|
29
|
+
s.rdoc_options = ['--charset=UTF-8']
|
30
|
+
|
31
|
+
s.files = %w[
|
32
|
+
README.md
|
33
|
+
Rakefile
|
34
|
+
pdfmult.gemspec
|
35
|
+
pdfmult.h2m
|
36
|
+
] +
|
37
|
+
Dir.glob('example*.*') +
|
38
|
+
Dir.glob('{bin,lib,man,test}/**/*')
|
39
|
+
|
40
|
+
s.add_development_dependency('rake')
|
41
|
+
s.add_development_dependency('minitest')
|
42
|
+
end
|
data/pdfmult.h2m
ADDED
@@ -0,0 +1,8 @@
|
|
1
|
+
[Name]
|
2
|
+
pdfmult \- puts multiple copies of a PDF page on one page
|
3
|
+
|
4
|
+
[Examples]
|
5
|
+
pdfmult sample.pdf # => sample_2.pdf (2 copies)
|
6
|
+
pdfmult -n 4 sample.pdf # => sample_4.pdf (4 copies)
|
7
|
+
pdfmult sample.pdf -o outfile.pdf # => outfile.pdf (2 copies)
|
8
|
+
pdfmult sample.pdf -p 3 # => processes 3 pages
|
data/test/sample.pdf
ADDED
Binary file
|
data/test/sample.tex
ADDED
@@ -0,0 +1,37 @@
|
|
1
|
+
\documentclass[paper=A4,fontsize=120pt,parskip=half,pagesize]{scrartcl}
|
2
|
+
|
3
|
+
\usepackage[utf8]{inputenc}
|
4
|
+
\usepackage[T1]{fontenc}
|
5
|
+
|
6
|
+
% Palatino / Helvetica
|
7
|
+
\usepackage{mathpazo}
|
8
|
+
\usepackage[scaled=.95]{helvet}
|
9
|
+
|
10
|
+
\usepackage[margin=2cm]{geometry}
|
11
|
+
|
12
|
+
% PDF-Metainformationen
|
13
|
+
\usepackage[pdftitle={Sample PDF Document},
|
14
|
+
pdfauthor={Marcus Stollsteimer},
|
15
|
+
pdfkeywords={},
|
16
|
+
pdfpagemode=UseNone,
|
17
|
+
pdfstartview=FitH,% Fit Width
|
18
|
+
bookmarks=false%
|
19
|
+
]{hyperref}
|
20
|
+
|
21
|
+
\pagestyle{empty}
|
22
|
+
|
23
|
+
\begin{document}
|
24
|
+
|
25
|
+
\centering
|
26
|
+
|
27
|
+
Page\\ One
|
28
|
+
|
29
|
+
\newpage
|
30
|
+
|
31
|
+
Page\\ Two
|
32
|
+
|
33
|
+
\newpage
|
34
|
+
|
35
|
+
Page\\ Three
|
36
|
+
|
37
|
+
\end{document}
|
@@ -0,0 +1,99 @@
|
|
1
|
+
#!/usr/bin/ruby -w
|
2
|
+
# test_pdfmult: Unit tests for the pdfmult script.
|
3
|
+
#
|
4
|
+
# Copyright (C) 2011-2012 Marcus Stollsteimer
|
5
|
+
|
6
|
+
require 'minitest/spec'
|
7
|
+
require 'minitest/autorun'
|
8
|
+
require 'pdfmult'
|
9
|
+
|
10
|
+
PROGNAME = 'test_pdfmult.rb'
|
11
|
+
PROGVERSION = '0.0.1'
|
12
|
+
|
13
|
+
SRCPATH = File.dirname(__FILE__)
|
14
|
+
|
15
|
+
|
16
|
+
describe Pdfmult::Optionparser do
|
17
|
+
|
18
|
+
it 'should return the correct default values' do
|
19
|
+
options = Pdfmult::Optionparser.parse!(['sample.pdf'])
|
20
|
+
expected = {
|
21
|
+
:infile => 'sample.pdf',
|
22
|
+
:outfile => 'sample_2.pdf',
|
23
|
+
:number => 2,
|
24
|
+
:pages => nil
|
25
|
+
}
|
26
|
+
options.must_equal expected
|
27
|
+
end
|
28
|
+
|
29
|
+
it 'should recognize the -n option and set the corresponding output filename' do
|
30
|
+
options = Pdfmult::Optionparser.parse!(['sample.pdf', '-n', '4'])
|
31
|
+
options[:outfile].must_equal 'sample_4.pdf'
|
32
|
+
options[:number].must_equal 4
|
33
|
+
end
|
34
|
+
|
35
|
+
it 'should not accept invalid -n option values' do
|
36
|
+
lambda { Pdfmult::Optionparser.parse!(['sample.pdf', '-n', '3']) }.must_raise OptionParser::InvalidArgument
|
37
|
+
end
|
38
|
+
|
39
|
+
it 'should recognize the -o option' do
|
40
|
+
options = Pdfmult::Optionparser.parse!(['sample.pdf', '-o', 'outfile.pdf'])
|
41
|
+
options[:outfile].must_equal 'outfile.pdf'
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'should recognize the -p option' do
|
45
|
+
options = Pdfmult::Optionparser.parse!(['sample.pdf', '-p', '4'])
|
46
|
+
options[:pages].must_equal 4
|
47
|
+
end
|
48
|
+
|
49
|
+
it 'should only accept positive -p option values' do
|
50
|
+
lambda { Pdfmult::Optionparser.parse!(['sample.pdf', '-p', '0.5']) }.must_raise OptionParser::InvalidArgument
|
51
|
+
lambda { Pdfmult::Optionparser.parse!(['sample.pdf', '-p', '0']) }.must_raise OptionParser::InvalidArgument
|
52
|
+
lambda { Pdfmult::Optionparser.parse!(['sample.pdf', '-p', '-1']) }.must_raise OptionParser::InvalidArgument
|
53
|
+
end
|
54
|
+
|
55
|
+
it 'should not accept wrong number of arguments' do
|
56
|
+
lambda { Pdfmult::Optionparser.parse!(['sample.pdf', 'sample2.pdf']) }.must_raise ArgumentError
|
57
|
+
lambda { Pdfmult::Optionparser.parse!(['']) }.must_raise ArgumentError
|
58
|
+
lambda { Pdfmult::Optionparser.parse!([]) }.must_raise ArgumentError
|
59
|
+
end
|
60
|
+
|
61
|
+
it 'should not accept invalid options' do
|
62
|
+
lambda { Pdfmult::Optionparser.parse!(['-x']) }.must_raise OptionParser::InvalidOption
|
63
|
+
end
|
64
|
+
end
|
65
|
+
|
66
|
+
|
67
|
+
describe Pdfmult::LaTeXDocument do
|
68
|
+
|
69
|
+
it 'should return the expected LaTeX code' do
|
70
|
+
document = Pdfmult::LaTeXDocument.new('sample.pdf', 8, 3)
|
71
|
+
document.to_s.split(/\n/)[0].must_equal "\\documentclass[a4paper,landscape]{article}"
|
72
|
+
document.to_s.split(/\n/)[-2].must_equal "\\includepdf[pages={3,3,3,3,3,3,3,3},nup=4x2]{sample.pdf}%"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
|
77
|
+
describe Pdfmult::PDFInfo do
|
78
|
+
|
79
|
+
before do
|
80
|
+
@sample_pdf = File.expand_path("#{SRCPATH}/sample.pdf")
|
81
|
+
end
|
82
|
+
|
83
|
+
describe 'when asked about the page count' do
|
84
|
+
it 'should return the page count for existing file and system tool' do
|
85
|
+
infocmd = Pdfmult::PDFInfo::PDFINFOCMD
|
86
|
+
skip("Skipped: `#{infocmd}' not available on the system") unless Pdfmult::PDFInfo.infocmd_available?
|
87
|
+
Pdfmult::PDFInfo.new(@sample_pdf).page_count.must_equal 3
|
88
|
+
Pdfmult::PDFInfo.new(@sample_pdf, :pdfinfocmd => infocmd).page_count.must_equal 3
|
89
|
+
end
|
90
|
+
|
91
|
+
it 'should return nil for non-existent files' do
|
92
|
+
Pdfmult::PDFInfo.new('not_a_file.pdf').page_count.must_be_nil
|
93
|
+
end
|
94
|
+
|
95
|
+
it "should return nil for non-existent `pdfinfo' system tool" do
|
96
|
+
Pdfmult::PDFInfo.new(@sample_pdf, :pdfinfocmd => 'not_a_command').page_count.must_be_nil
|
97
|
+
end
|
98
|
+
end
|
99
|
+
end
|
metadata
ADDED
@@ -0,0 +1,105 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdfmult
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 23
|
5
|
+
prerelease:
|
6
|
+
segments:
|
7
|
+
- 1
|
8
|
+
- 0
|
9
|
+
- 0
|
10
|
+
version: 1.0.0
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Marcus Stollsteimer
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2012-03-15 00:00:00 Z
|
19
|
+
dependencies:
|
20
|
+
- !ruby/object:Gem::Dependency
|
21
|
+
name: rake
|
22
|
+
prerelease: false
|
23
|
+
requirement: &id001 !ruby/object:Gem::Requirement
|
24
|
+
none: false
|
25
|
+
requirements:
|
26
|
+
- - ">="
|
27
|
+
- !ruby/object:Gem::Version
|
28
|
+
hash: 3
|
29
|
+
segments:
|
30
|
+
- 0
|
31
|
+
version: "0"
|
32
|
+
type: :development
|
33
|
+
version_requirements: *id001
|
34
|
+
- !ruby/object:Gem::Dependency
|
35
|
+
name: minitest
|
36
|
+
prerelease: false
|
37
|
+
requirement: &id002 !ruby/object:Gem::Requirement
|
38
|
+
none: false
|
39
|
+
requirements:
|
40
|
+
- - ">="
|
41
|
+
- !ruby/object:Gem::Version
|
42
|
+
hash: 3
|
43
|
+
segments:
|
44
|
+
- 0
|
45
|
+
version: "0"
|
46
|
+
type: :development
|
47
|
+
version_requirements: *id002
|
48
|
+
description: pdfmult is a command line tool that rearranges multiple copies of a PDF page (shrunken) on one page.
|
49
|
+
email: sto.mar@web.de
|
50
|
+
executables:
|
51
|
+
- pdfmult
|
52
|
+
extensions: []
|
53
|
+
|
54
|
+
extra_rdoc_files: []
|
55
|
+
|
56
|
+
files:
|
57
|
+
- README.md
|
58
|
+
- Rakefile
|
59
|
+
- pdfmult.gemspec
|
60
|
+
- pdfmult.h2m
|
61
|
+
- example1.fig
|
62
|
+
- example1.png
|
63
|
+
- example2.fig
|
64
|
+
- example2.png
|
65
|
+
- bin/pdfmult
|
66
|
+
- lib/pdfmult.rb
|
67
|
+
- man/pdfmult.1
|
68
|
+
- test/sample.tex
|
69
|
+
- test/test_pdfmult.rb
|
70
|
+
- test/sample.pdf
|
71
|
+
homepage: https://github.com/stomar/pdfmult/
|
72
|
+
licenses:
|
73
|
+
- GPL-3
|
74
|
+
post_install_message:
|
75
|
+
rdoc_options:
|
76
|
+
- --charset=UTF-8
|
77
|
+
require_paths:
|
78
|
+
- lib
|
79
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
80
|
+
none: false
|
81
|
+
requirements:
|
82
|
+
- - ">="
|
83
|
+
- !ruby/object:Gem::Version
|
84
|
+
hash: 3
|
85
|
+
segments:
|
86
|
+
- 0
|
87
|
+
version: "0"
|
88
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
89
|
+
none: false
|
90
|
+
requirements:
|
91
|
+
- - ">="
|
92
|
+
- !ruby/object:Gem::Version
|
93
|
+
hash: 3
|
94
|
+
segments:
|
95
|
+
- 0
|
96
|
+
version: "0"
|
97
|
+
requirements:
|
98
|
+
- pdflatex and the pdfpages package
|
99
|
+
rubyforge_project: pdfmult
|
100
|
+
rubygems_version: 1.7.2
|
101
|
+
signing_key:
|
102
|
+
specification_version: 3
|
103
|
+
summary: pdfmult - puts multiple copies of a PDF page on one page
|
104
|
+
test_files:
|
105
|
+
- test/test_pdfmult.rb
|