pdfmult 1.0.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/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
|