hexapdf 0.10.0 → 0.11.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/CHANGELOG.md +33 -0
- data/CONTRIBUTERS +1 -1
- data/Rakefile +35 -50
- data/VERSION +1 -1
- data/lib/hexapdf/cli.rb +4 -0
- data/lib/hexapdf/cli/command.rb +6 -2
- data/lib/hexapdf/cli/image2pdf.rb +141 -0
- data/lib/hexapdf/cli/info.rb +1 -1
- data/lib/hexapdf/cli/inspect.rb +32 -2
- data/lib/hexapdf/cli/modify.rb +1 -1
- data/lib/hexapdf/cli/optimize.rb +1 -1
- data/lib/hexapdf/cli/watermark.rb +130 -0
- data/lib/hexapdf/composer.rb +2 -2
- data/lib/hexapdf/configuration.rb +7 -1
- data/lib/hexapdf/content/canvas.rb +2 -2
- data/lib/hexapdf/content/graphic_object/arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/endpoint_arc.rb +2 -2
- data/lib/hexapdf/content/graphic_object/geom2d.rb +1 -1
- data/lib/hexapdf/content/graphic_object/solid_arc.rb +1 -1
- data/lib/hexapdf/dictionary.rb +11 -3
- data/lib/hexapdf/dictionary_fields.rb +32 -3
- data/lib/hexapdf/document.rb +7 -3
- data/lib/hexapdf/document/files.rb +1 -1
- data/lib/hexapdf/document/fonts.rb +21 -1
- data/lib/hexapdf/document/pages.rb +2 -2
- data/lib/hexapdf/encryption/standard_security_handler.rb +2 -2
- data/lib/hexapdf/font/cmap/parser.rb +1 -1
- data/lib/hexapdf/font/true_type/table/head.rb +2 -2
- data/lib/hexapdf/font/true_type/table/os2.rb +4 -4
- data/lib/hexapdf/font/true_type_wrapper.rb +16 -16
- data/lib/hexapdf/font/type1_wrapper.rb +16 -16
- data/lib/hexapdf/font_loader.rb +2 -0
- data/lib/hexapdf/font_loader/from_configuration.rb +5 -0
- data/lib/hexapdf/font_loader/standard14.rb +5 -0
- data/lib/hexapdf/image_loader/png.rb +1 -1
- data/lib/hexapdf/layout/box.rb +2 -2
- data/lib/hexapdf/layout/image_box.rb +1 -1
- data/lib/hexapdf/layout/style.rb +50 -24
- data/lib/hexapdf/layout/text_box.rb +1 -1
- data/lib/hexapdf/layout/text_fragment.rb +2 -2
- data/lib/hexapdf/layout/text_layouter.rb +14 -10
- data/lib/hexapdf/name_tree_node.rb +3 -3
- data/lib/hexapdf/number_tree_node.rb +3 -3
- data/lib/hexapdf/pdf_array.rb +207 -0
- data/lib/hexapdf/rectangle.rb +12 -12
- data/lib/hexapdf/serializer.rb +1 -1
- data/lib/hexapdf/stream.rb +6 -4
- data/lib/hexapdf/task/optimize.rb +3 -3
- data/lib/hexapdf/type.rb +2 -0
- data/lib/hexapdf/type/acro_form.rb +51 -0
- data/lib/hexapdf/type/acro_form/field.rb +129 -0
- data/lib/hexapdf/type/acro_form/form.rb +124 -0
- data/lib/hexapdf/type/action.rb +1 -1
- data/lib/hexapdf/type/actions/go_to.rb +1 -1
- data/lib/hexapdf/type/actions/go_to_r.rb +1 -1
- data/lib/hexapdf/type/actions/launch.rb +1 -1
- data/lib/hexapdf/type/annotation.rb +2 -2
- data/lib/hexapdf/type/annotations.rb +1 -0
- data/lib/hexapdf/type/annotations/link.rb +4 -15
- data/lib/hexapdf/type/annotations/markup_annotation.rb +2 -1
- data/lib/hexapdf/type/annotations/text.rb +3 -6
- data/lib/hexapdf/type/annotations/widget.rb +90 -0
- data/lib/hexapdf/type/catalog.rb +12 -9
- data/lib/hexapdf/type/cid_font.rb +3 -3
- data/lib/hexapdf/type/file_specification.rb +2 -2
- data/lib/hexapdf/type/font_descriptor.rb +5 -2
- data/lib/hexapdf/type/font_simple.rb +1 -1
- data/lib/hexapdf/type/font_type0.rb +1 -1
- data/lib/hexapdf/type/font_type3.rb +1 -1
- data/lib/hexapdf/type/form.rb +2 -2
- data/lib/hexapdf/type/graphics_state_parameter.rb +11 -6
- data/lib/hexapdf/type/icon_fit.rb +58 -0
- data/lib/hexapdf/type/image.rb +14 -8
- data/lib/hexapdf/type/info.rb +2 -1
- data/lib/hexapdf/type/page.rb +4 -4
- data/lib/hexapdf/type/page_tree_node.rb +3 -7
- data/lib/hexapdf/type/resources.rb +1 -1
- data/lib/hexapdf/type/trailer.rb +4 -4
- data/lib/hexapdf/type/viewer_preferences.rb +7 -4
- data/lib/hexapdf/type/xref_stream.rb +2 -2
- data/lib/hexapdf/utils/sorted_tree_node.rb +1 -1
- data/lib/hexapdf/version.rb +1 -1
- data/man/man1/hexapdf.1 +77 -8
- data/test/hexapdf/content/test_canvas.rb +2 -2
- data/test/hexapdf/content/test_processor.rb +3 -3
- data/test/hexapdf/document/test_files.rb +4 -4
- data/test/hexapdf/document/test_fonts.rb +13 -1
- data/test/hexapdf/document/test_images.rb +6 -6
- data/test/hexapdf/document/test_pages.rb +8 -8
- data/test/hexapdf/encryption/test_security_handler.rb +7 -7
- data/test/hexapdf/encryption/test_standard_security_handler.rb +5 -5
- data/test/hexapdf/font/test_true_type_wrapper.rb +2 -2
- data/test/hexapdf/font_loader/test_from_configuration.rb +4 -0
- data/test/hexapdf/font_loader/test_standard14.rb +10 -0
- data/test/hexapdf/image_loader/test_jpeg.rb +1 -1
- data/test/hexapdf/image_loader/test_png.rb +3 -3
- data/test/hexapdf/layout/test_box.rb +2 -2
- data/test/hexapdf/layout/test_frame.rb +1 -1
- data/test/hexapdf/layout/test_image_box.rb +1 -1
- data/test/hexapdf/layout/test_style.rb +18 -13
- data/test/hexapdf/layout/test_text_box.rb +1 -1
- data/test/hexapdf/layout/test_text_layouter.rb +11 -6
- data/test/hexapdf/task/test_dereference.rb +2 -2
- data/test/hexapdf/task/test_optimize.rb +11 -11
- data/test/hexapdf/test_composer.rb +1 -1
- data/test/hexapdf/test_dictionary.rb +10 -2
- data/test/hexapdf/test_dictionary_fields.rb +27 -3
- data/test/hexapdf/test_document.rb +16 -15
- data/test/hexapdf/test_importer.rb +4 -4
- data/test/hexapdf/test_object.rb +1 -1
- data/test/hexapdf/test_pdf_array.rb +162 -0
- data/test/hexapdf/test_rectangle.rb +3 -5
- data/test/hexapdf/test_serializer.rb +1 -1
- data/test/hexapdf/test_stream.rb +1 -0
- data/test/hexapdf/test_writer.rb +3 -3
- data/test/hexapdf/type/acro_form/test_field.rb +85 -0
- data/test/hexapdf/type/acro_form/test_form.rb +69 -0
- data/test/hexapdf/type/annotations/test_text.rb +2 -6
- data/test/hexapdf/type/annotations/test_widget.rb +24 -0
- data/test/hexapdf/type/test_annotation.rb +1 -1
- data/test/hexapdf/type/test_catalog.rb +1 -1
- data/test/hexapdf/type/test_cid_font.rb +3 -3
- data/test/hexapdf/type/test_font.rb +2 -2
- data/test/hexapdf/type/test_font_descriptor.rb +2 -1
- data/test/hexapdf/type/test_font_simple.rb +3 -3
- data/test/hexapdf/type/test_font_true_type.rb +6 -6
- data/test/hexapdf/type/test_font_type0.rb +5 -5
- data/test/hexapdf/type/test_font_type1.rb +8 -8
- data/test/hexapdf/type/test_font_type3.rb +4 -4
- data/test/hexapdf/type/test_image.rb +16 -12
- data/test/hexapdf/type/test_page.rb +11 -11
- data/test/hexapdf/type/test_page_tree_node.rb +20 -20
- data/test/hexapdf/type/test_resources.rb +6 -6
- data/test/hexapdf/type/test_trailer.rb +5 -2
- data/test/hexapdf/type/test_xref_stream.rb +1 -0
- data/test/hexapdf/utils/test_sorted_tree_node.rb +35 -35
- metadata +23 -7
- data/test/hexapdf/type/annotations/test_link.rb +0 -19
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: d9c9409476d9ff9efaf2a8c0fb2b2623f660676c19e0d920659f6d719a783ee1
|
4
|
+
data.tar.gz: cb266922c5cdb6749e7a9954141e2b8b2094fcd44968bfa384e62478a184161c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7c7d5fb9e817d5a4a8fc7ad3f26deb075afa9dd504fda9dd7801dabbb76bcf819734cb86918ecb1c553e767125edfd47672cfeacdd648afbda81ab198e02f96f
|
7
|
+
data.tar.gz: bafff7b14203d534cacf94fdfaf493657c05255fb1caf431fd0cc8b7ebdcfb4470d49a0d02a5d72c96fea51f0c4bc0fa6b9aaca89caf0a190e6879be1b49fbb3
|
data/CHANGELOG.md
CHANGED
@@ -1,3 +1,36 @@
|
|
1
|
+
## 0.11.0 - 2019-11-19
|
2
|
+
|
3
|
+
### Added
|
4
|
+
|
5
|
+
* [HexaPDF::PDFArray] to wrap arrays and allow automatic resolution of
|
6
|
+
references like with [HexaPDF::Dictionary] - MAY BREAK THINGS!
|
7
|
+
* CLI command `hexapdf watermark` to apply a watermark PDF as background or
|
8
|
+
stamp onto another PDF file
|
9
|
+
* CLI command `hexapdf image2pdf` to convert images into a PDF file
|
10
|
+
* [HexaPDF::DictionaryFields::Field#allowed_values] to allow constraining a
|
11
|
+
field to certain allowed values
|
12
|
+
* [HexaPDF::Document::Fonts#configured_fonts] to return all font variants that
|
13
|
+
are configured and available for adding to a document
|
14
|
+
* [HexaPDF::Type::Annotations::Widget] and associated classes
|
15
|
+
* [HexaPDF::Type::AcroForm::Form] and [HexaPDF::Type::AcroForm::Field] for basic
|
16
|
+
AcroForm support
|
17
|
+
|
18
|
+
### Changed
|
19
|
+
|
20
|
+
* Use Reline for interactive mode of `hexapdf inspect` if available
|
21
|
+
* [HexaPDF::DictionaryFields::Field::new] to use keyword arguments
|
22
|
+
* Update the field information for implemented PDF types to include the allowed
|
23
|
+
values where possible
|
24
|
+
* Interface of font loader objects to allow another method `available_fonts` for
|
25
|
+
returning all available fonts
|
26
|
+
* [HexaPDF::Layout::Style] to check for valid values where possible
|
27
|
+
|
28
|
+
### Fixed
|
29
|
+
|
30
|
+
* Line spacing of empty lines for [HexaPDF::Layout::TextLayouter]
|
31
|
+
* Handling of `/DecodeParms` when exporting to PNG images
|
32
|
+
|
33
|
+
|
1
34
|
## 0.10.0 - 2019-10-02
|
2
35
|
|
3
36
|
### Added
|
data/CONTRIBUTERS
CHANGED
data/Rakefile
CHANGED
@@ -1,9 +1,9 @@
|
|
1
|
+
# -*- coding: utf-8 -*-
|
1
2
|
require 'rake/testtask'
|
2
3
|
require 'rake/clean'
|
3
4
|
require 'rubygems/package_task'
|
4
5
|
|
5
|
-
|
6
|
-
require 'hexapdf'
|
6
|
+
require_relative 'lib/hexapdf/version'
|
7
7
|
|
8
8
|
Rake::TestTask.new do |t|
|
9
9
|
t.libs << 'test'
|
@@ -13,19 +13,6 @@ Rake::TestTask.new do |t|
|
|
13
13
|
end
|
14
14
|
|
15
15
|
namespace :dev do
|
16
|
-
PKG_FILES = FileList.new([
|
17
|
-
'Rakefile',
|
18
|
-
'LICENSE', 'agpl-3.0.txt',
|
19
|
-
'README.md', 'CHANGELOG.md',
|
20
|
-
'VERSION', 'CONTRIBUTERS',
|
21
|
-
'bin/*',
|
22
|
-
'lib/**/*.rb',
|
23
|
-
'man/man1/hexapdf.1',
|
24
|
-
'data/**/*',
|
25
|
-
'examples/*',
|
26
|
-
'test/**/*'
|
27
|
-
])
|
28
|
-
|
29
16
|
CLOBBER << "man/man1/hexapdf.1"
|
30
17
|
file 'man/man1/hexapdf.1' => ['man/man1/hexapdf.1.md'] do
|
31
18
|
puts "Generating hexapdf man page"
|
@@ -35,7 +22,7 @@ namespace :dev do
|
|
35
22
|
CLOBBER << "VERSION"
|
36
23
|
file 'VERSION' do
|
37
24
|
puts "Generating VERSION file"
|
38
|
-
File.open('VERSION', 'w+') {|file| file.write(HexaPDF::VERSION + "\n")}
|
25
|
+
File.open('VERSION', 'w+') {|file| file.write(HexaPDF::VERSION + "\n") }
|
39
26
|
end
|
40
27
|
|
41
28
|
CLOBBER << 'CONTRIBUTERS'
|
@@ -46,35 +33,8 @@ namespace :dev do
|
|
46
33
|
`git log | grep ^Author: | sed 's/^Author: //' | sort | uniq -c | sort -nr >> CONTRIBUTERS`
|
47
34
|
end
|
48
35
|
|
49
|
-
|
50
|
-
|
51
|
-
s.version = HexaPDF::VERSION
|
52
|
-
s.summary = "HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby"
|
53
|
-
s.description = "HexaPDF is a pure Ruby library with an accompanying application for " \
|
54
|
-
"working with PDF files.\n\nIn short, it allows creating new PDF files, manipulating " \
|
55
|
-
"existing PDF files, merging multiple PDF files into one, extracting meta information, " \
|
56
|
-
"text, images and files from PDF files, securing PDF files by encrypting them and " \
|
57
|
-
"optimizing PDF files for smaller file size or other criteria.\n\nHexaPDF was designed " \
|
58
|
-
"with ease of use and performance in mind. It uses lazy loading and lazy computing when " \
|
59
|
-
"possible and tries to produce small PDF files by default."
|
60
|
-
s.license = 'AGPL-3.0'
|
61
|
-
|
62
|
-
s.files = PKG_FILES.to_a
|
63
|
-
|
64
|
-
s.require_path = 'lib'
|
65
|
-
s.executables = ['hexapdf']
|
66
|
-
s.add_dependency('cmdparse', '~> 3.0', '>= 3.0.3')
|
67
|
-
s.add_dependency('geom2d', '~> 0.2')
|
68
|
-
s.add_development_dependency('kramdown', '~> 1.0', '>= 1.13.0')
|
69
|
-
s.add_development_dependency('rubocop', '~> 0.58', '>= 0.58.2')
|
70
|
-
s.required_ruby_version = '>= 2.4'
|
71
|
-
|
72
|
-
s.author = 'Thomas Leitner'
|
73
|
-
s.email = 't_leitner@gmx.at'
|
74
|
-
s.homepage = "https://hexapdf.gettalong.org"
|
75
|
-
end
|
76
|
-
|
77
|
-
Gem::PackageTask.new(spec) do |pkg|
|
36
|
+
ENV['REAL_GEM'] = "true"
|
37
|
+
Gem::PackageTask.new(eval(File.read('hexapdf.gemspec'), binding, 'hexapdf.gemspec')) do |pkg|
|
78
38
|
pkg.need_zip = true
|
79
39
|
pkg.need_tar = true
|
80
40
|
end
|
@@ -88,11 +48,36 @@ namespace :dev do
|
|
88
48
|
desc 'Release HexaPDF version ' + HexaPDF::VERSION
|
89
49
|
task release: [:clobber, :package, :publish_files]
|
90
50
|
|
91
|
-
|
92
|
-
task :
|
93
|
-
puts "
|
94
|
-
|
95
|
-
|
51
|
+
desc "Set-up everything for development"
|
52
|
+
task :setup do
|
53
|
+
puts "Installing required runtime and development gems:"
|
54
|
+
resolver = Gem::Resolver.for_current_gems(spec.dependencies)
|
55
|
+
resolver.ignore_dependencies = true
|
56
|
+
resolver.soft_missing = true
|
57
|
+
resolver.resolve
|
58
|
+
spec.dependencies.each do |dependency|
|
59
|
+
if resolver.missing.find {|dep_request| dep_request.dependency == dependency }
|
60
|
+
print "✗ #{dependency.name} - installing it..."
|
61
|
+
Gem.install(dependency.name, dependency.requirement, prerelease: true)
|
62
|
+
puts " done"
|
63
|
+
else
|
64
|
+
puts "✓ #{dependency.name}"
|
65
|
+
end
|
66
|
+
end
|
67
|
+
|
68
|
+
puts
|
69
|
+
puts "The following binaries are needed for the tests:"
|
70
|
+
{
|
71
|
+
'pngtopnm' => 'sudo apt install netpbm',
|
72
|
+
'pngcheck' => 'sudo apt install pngcheck',
|
73
|
+
}.each do |name, install_command|
|
74
|
+
`which #{name} 2>&1`
|
75
|
+
if $?.exitstatus == 0
|
76
|
+
puts "✓ #{name}"
|
77
|
+
else
|
78
|
+
puts "✗ #{name} (#{install_command})"
|
79
|
+
end
|
80
|
+
end
|
96
81
|
end
|
97
82
|
|
98
83
|
CODING_LINE = "# -*- encoding: utf-8; frozen_string_literal: true -*-\n"
|
data/VERSION
CHANGED
@@ -1 +1 @@
|
|
1
|
-
0.
|
1
|
+
0.11.0
|
data/lib/hexapdf/cli.rb
CHANGED
@@ -44,6 +44,8 @@ require 'hexapdf/cli/optimize'
|
|
44
44
|
require 'hexapdf/cli/images'
|
45
45
|
require 'hexapdf/cli/batch'
|
46
46
|
require 'hexapdf/cli/split'
|
47
|
+
require 'hexapdf/cli/watermark'
|
48
|
+
require 'hexapdf/cli/image2pdf'
|
47
49
|
require 'hexapdf/version'
|
48
50
|
require 'hexapdf/document'
|
49
51
|
|
@@ -95,6 +97,8 @@ module HexaPDF
|
|
95
97
|
add_command(HexaPDF::CLI::Merge.new)
|
96
98
|
add_command(HexaPDF::CLI::Batch.new)
|
97
99
|
add_command(HexaPDF::CLI::Split.new)
|
100
|
+
add_command(HexaPDF::CLI::Watermark.new)
|
101
|
+
add_command(HexaPDF::CLI::Image2PDF.new)
|
98
102
|
add_command(CmdParse::HelpCommand.new)
|
99
103
|
version_command = CmdParse::VersionCommand.new(add_switches: false)
|
100
104
|
add_command(version_command)
|
data/lib/hexapdf/cli/command.rb
CHANGED
@@ -57,7 +57,7 @@ module HexaPDF
|
|
57
57
|
|
58
58
|
include Extensions
|
59
59
|
|
60
|
-
def initialize(*args, &block) #:nodoc:
|
60
|
+
def initialize(*args, **kwargs, &block) #:nodoc:
|
61
61
|
super
|
62
62
|
@out_options = OpenStruct.new
|
63
63
|
@out_options.compact = true
|
@@ -82,7 +82,7 @@ module HexaPDF
|
|
82
82
|
# If +out_file+ is given, the document is written to it after yielding.
|
83
83
|
def with_document(file, password: nil, out_file: nil) #:yield: document
|
84
84
|
if file == out_file
|
85
|
-
doc = HexaPDF::Document.open(file, pdf_options(password))
|
85
|
+
doc = HexaPDF::Document.open(file, **pdf_options(password))
|
86
86
|
else
|
87
87
|
file_io = File.open(file, 'rb')
|
88
88
|
doc = HexaPDF::Document.new(io: file_io, **pdf_options(password))
|
@@ -143,6 +143,8 @@ module HexaPDF
|
|
143
143
|
#
|
144
144
|
# See: #out_options, #apply_optimization_options
|
145
145
|
def define_optimization_options
|
146
|
+
options.separator("")
|
147
|
+
options.separator("Optimization options:")
|
146
148
|
options.on("--[no-]compact", "Delete unnecessary PDF objects (default: " \
|
147
149
|
"#{@out_options.compact})") do |c|
|
148
150
|
@out_options.compact = c
|
@@ -176,6 +178,8 @@ module HexaPDF
|
|
176
178
|
#
|
177
179
|
# See: #out_options, #apply_encryption_options
|
178
180
|
def define_encryption_options
|
181
|
+
options.separator("")
|
182
|
+
options.separator("Encryption options:")
|
179
183
|
options.on("--decrypt", "Remove any encryption") do
|
180
184
|
@out_options.encryption = :remove
|
181
185
|
end
|
@@ -0,0 +1,141 @@
|
|
1
|
+
# -*- encoding: utf-8; frozen_string_literal: true -*-
|
2
|
+
#
|
3
|
+
#--
|
4
|
+
# This file is part of HexaPDF.
|
5
|
+
#
|
6
|
+
# HexaPDF - A Versatile PDF Creation and Manipulation Library For Ruby
|
7
|
+
# Copyright (C) 2014-2019 Thomas Leitner
|
8
|
+
#
|
9
|
+
# HexaPDF is free software: you can redistribute it and/or modify it
|
10
|
+
# under the terms of the GNU Affero General Public License version 3 as
|
11
|
+
# published by the Free Software Foundation with the addition of the
|
12
|
+
# following permission added to Section 15 as permitted in Section 7(a):
|
13
|
+
# FOR ANY PART OF THE COVERED WORK IN WHICH THE COPYRIGHT IS OWNED BY
|
14
|
+
# THOMAS LEITNER, THOMAS LEITNER DISCLAIMS THE WARRANTY OF NON
|
15
|
+
# INFRINGEMENT OF THIRD PARTY RIGHTS.
|
16
|
+
#
|
17
|
+
# HexaPDF is distributed in the hope that it will be useful, but WITHOUT
|
18
|
+
# ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
19
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Affero General Public
|
20
|
+
# License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Affero General Public License
|
23
|
+
# along with HexaPDF. If not, see <http://www.gnu.org/licenses/>.
|
24
|
+
#
|
25
|
+
# The interactive user interfaces in modified source and object code
|
26
|
+
# versions of HexaPDF must display Appropriate Legal Notices, as required
|
27
|
+
# under Section 5 of the GNU Affero General Public License version 3.
|
28
|
+
#
|
29
|
+
# In accordance with Section 7(b) of the GNU Affero General Public
|
30
|
+
# License, a covered work must retain the producer line in every PDF that
|
31
|
+
# is created or manipulated using HexaPDF.
|
32
|
+
#
|
33
|
+
# If the GNU Affero General Public License doesn't fit your need,
|
34
|
+
# commercial licenses are available at <https://gettalong.at/hexapdf/>.
|
35
|
+
#++
|
36
|
+
|
37
|
+
require 'hexapdf/cli/command'
|
38
|
+
|
39
|
+
module HexaPDF
|
40
|
+
module CLI
|
41
|
+
|
42
|
+
# Converts one or more images into a PDF file.
|
43
|
+
class Image2PDF < Command
|
44
|
+
|
45
|
+
def initialize #:nodoc:
|
46
|
+
super('image2pdf', takes_commands: false)
|
47
|
+
short_desc("Convert one or more images into a PDF file")
|
48
|
+
long_desc(<<~EOF)
|
49
|
+
This command converts one or more images into a single PDF file. The various options allow
|
50
|
+
setting a page size, scaling the images and defining margins.
|
51
|
+
EOF
|
52
|
+
|
53
|
+
options.on("-p", "--page-size SIZE", "The PDF page size. Either auto which chooses a " \
|
54
|
+
"size based on the image size or a valid page size like A4, A4-landscape " \
|
55
|
+
"or 595x842. Default: auto") do |page_size|
|
56
|
+
@media_box = case page_size
|
57
|
+
when 'auto'
|
58
|
+
:auto
|
59
|
+
when /(\d+(?:\.\d+)?)x(\d+(?:\.\d+)?)/
|
60
|
+
[0, 0, $1.to_f, $2.to_f]
|
61
|
+
else
|
62
|
+
orientation = :portrait
|
63
|
+
if page_size.end_with?('-landscape')
|
64
|
+
orientation = :landscape
|
65
|
+
page_size.delete_suffix!('-landscape')
|
66
|
+
end
|
67
|
+
HexaPDF::Type::Page.media_box(page_size.to_sym, orientation: orientation)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
options.on("--[no-]auto-rotate", "Automatically rotate pages based on image dimesions. " \
|
71
|
+
"Default: true") do |auto_rotate|
|
72
|
+
@auto_rotate = auto_rotate
|
73
|
+
end
|
74
|
+
options.on("-s", "--scale SCALE", Integer, "Defines how the images should be scaled. " \
|
75
|
+
"Either fit to fit the image to the page size or a number specifying the " \
|
76
|
+
"minimum pixels per inch. Default: fit") do |scale|
|
77
|
+
@scale = case scale
|
78
|
+
when 'fit' then :fit
|
79
|
+
else scale.to_f
|
80
|
+
end
|
81
|
+
end
|
82
|
+
options.on("-m", "--margins MARGINS", Array, "Defines the margins around the image, " \
|
83
|
+
"either with a single number or four numbers (top, right, bottom, left) " \
|
84
|
+
"separated by commas. Default: 0") do |margins|
|
85
|
+
@margins = case margins.size
|
86
|
+
when 1 then margins.map!(&:to_f) * 4
|
87
|
+
when 4 then margins.map!(&:to_f)
|
88
|
+
else
|
89
|
+
raise OptionParser::InvalidArgument, "#{margins.join(',')} (1 or 4 " \
|
90
|
+
"numbers needed)"
|
91
|
+
end
|
92
|
+
end
|
93
|
+
define_optimization_options
|
94
|
+
define_encryption_options
|
95
|
+
|
96
|
+
@media_box = :auto
|
97
|
+
@auto_rotate = true
|
98
|
+
@scale = :fit
|
99
|
+
@margins = [0, 0, 0, 0]
|
100
|
+
end
|
101
|
+
|
102
|
+
def execute(out_file, *images) #:nodoc:
|
103
|
+
maybe_raise_on_existing_file(out_file)
|
104
|
+
|
105
|
+
out = HexaPDF::Document.new
|
106
|
+
|
107
|
+
images.each do |image_file|
|
108
|
+
image = out.images.add(image_file)
|
109
|
+
iw = image.info.width.to_f
|
110
|
+
ih = image.info.height.to_f
|
111
|
+
if @scale != :fit
|
112
|
+
iw *= 72 / @scale
|
113
|
+
ih *= 72 / @scale
|
114
|
+
end
|
115
|
+
|
116
|
+
media_box = (@media_box == :auto ? [0, 0, iw, ih] : @media_box.dup)
|
117
|
+
if @auto_rotate && (ih > iw) != (media_box[3] > media_box[2]) &&
|
118
|
+
(iw > media_box[2] || ih > media_box[3])
|
119
|
+
media_box[2], media_box[3] = media_box[3], media_box[2]
|
120
|
+
end
|
121
|
+
page = out.pages.add(media_box)
|
122
|
+
|
123
|
+
pw = page.box(:media).width.to_f - @margins[1] - @margins[3]
|
124
|
+
ph = page.box(:media).height.to_f - @margins[0] - @margins[2]
|
125
|
+
if @scale == :fit || iw > pw || ih > ph
|
126
|
+
ratio = [pw / iw, ph / ih].min
|
127
|
+
iw, ih = iw * ratio, ih * ratio
|
128
|
+
end
|
129
|
+
x, y = @margins[3] + (pw - iw) / 2, @margins[2] + (ph - ih) / 2
|
130
|
+
page.canvas.image(image, at: [x, y], width: iw, height: ih)
|
131
|
+
end
|
132
|
+
|
133
|
+
apply_encryption_options(out)
|
134
|
+
apply_optimization_options(out)
|
135
|
+
write_document(out, out_file)
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
|
140
|
+
end
|
141
|
+
end
|
data/lib/hexapdf/cli/info.rb
CHANGED
@@ -78,7 +78,7 @@ module HexaPDF
|
|
78
78
|
def output_info(file) # :nodoc:
|
79
79
|
options = pdf_options(@password)
|
80
80
|
options[:config]['document.auto_decrypt'] = @auto_decrypt
|
81
|
-
HexaPDF::Document.open(file, options) do |doc|
|
81
|
+
HexaPDF::Document.open(file, **options) do |doc|
|
82
82
|
output_line("File name", file)
|
83
83
|
output_line("File size", File.stat(file).size.to_s + " bytes")
|
84
84
|
@auto_decrypt && INFO_KEYS.each do |name|
|
data/lib/hexapdf/cli/inspect.rb
CHANGED
@@ -70,9 +70,17 @@ module HexaPDF
|
|
70
70
|
with_document(file, password: @password) do |doc|
|
71
71
|
@doc = doc
|
72
72
|
if commands.empty?
|
73
|
+
begin
|
74
|
+
require 'reline'
|
75
|
+
Reline.completion_proc = RELINE_COMPLETION_PROC
|
76
|
+
Reline.completion_append_character = " "
|
77
|
+
rescue LoadError
|
78
|
+
if command_parser.verbosity_info?
|
79
|
+
$stderr.puts("Library reline not available, history and line editing not available")
|
80
|
+
end
|
81
|
+
end
|
73
82
|
while true
|
74
|
-
|
75
|
-
input = $stdin.gets
|
83
|
+
input = read_input
|
76
84
|
(puts; break) unless input
|
77
85
|
commands = input.scan(/(["'])(.+?)\1|(\S+)/).map {|a| a[1] || a[2] }
|
78
86
|
break if execute_commands(commands)
|
@@ -85,6 +93,28 @@ module HexaPDF
|
|
85
93
|
|
86
94
|
private
|
87
95
|
|
96
|
+
# :nodoc:
|
97
|
+
COMMAND_LIST = %w[object recursive stream raw-stream xref catalog trailer pages
|
98
|
+
page-count search quit help]
|
99
|
+
# :nodoc:
|
100
|
+
RELINE_COMPLETION_PROC = proc do |s|
|
101
|
+
if s.empty?
|
102
|
+
COMMAND_DESCRIPTIONS.map {|cmd, desc| cmd.ljust(35) << desc }
|
103
|
+
else
|
104
|
+
COMMAND_LIST.grep(/^#{Regexp.escape(s)}/)
|
105
|
+
end
|
106
|
+
end
|
107
|
+
|
108
|
+
# Returns one line of input, using Reline if available.
|
109
|
+
def read_input
|
110
|
+
if Object.const_defined?("Reline")
|
111
|
+
Reline.readline("cmd> ", true)
|
112
|
+
else
|
113
|
+
print "cmd> "
|
114
|
+
$stdin.gets
|
115
|
+
end
|
116
|
+
end
|
117
|
+
|
88
118
|
def execute_commands(data) #:nodoc:
|
89
119
|
data.map! {|item| item == ";" ? nil : item }
|
90
120
|
until data.empty?
|
data/lib/hexapdf/cli/modify.rb
CHANGED
@@ -93,7 +93,7 @@ module HexaPDF
|
|
93
93
|
# Arranges the pages of the document as specified with the --pages option.
|
94
94
|
def arrange_pages(doc)
|
95
95
|
all_pages = doc.pages.to_a
|
96
|
-
new_page_tree = doc.add(Type: :Pages)
|
96
|
+
new_page_tree = doc.add({Type: :Pages})
|
97
97
|
parse_pages_specification(@pages, all_pages.length).each do |index, rotation|
|
98
98
|
page = all_pages[index]
|
99
99
|
page.value.update(page.copy_inherited_values)
|
data/lib/hexapdf/cli/optimize.rb
CHANGED
@@ -81,7 +81,7 @@ module HexaPDF
|
|
81
81
|
|
82
82
|
# Optimizes the page tree by flattening it and deleting unsed objects.
|
83
83
|
def optimize_page_tree(doc)
|
84
|
-
page_tree = doc.add(Type: :Pages)
|
84
|
+
page_tree = doc.add({Type: :Pages})
|
85
85
|
retained = {page_tree.data => true}
|
86
86
|
doc.pages.each do |page|
|
87
87
|
page.value.update(page.copy_inherited_values)
|