pdf_outline_editor 0.1.0-java
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.
- checksums.yaml +7 -0
- data/README.md +51 -0
- data/exe/pdf_outline_editor +11 -0
- data/lib/pdf_outline_editor.rb +17 -0
- data/lib/pdf_outline_editor/commands/dump_command.rb +68 -0
- data/lib/pdf_outline_editor/commands/init_command.rb +70 -0
- data/lib/pdf_outline_editor/commands/load_command.rb +80 -0
- data/lib/pdf_outline_editor/dumper.rb +74 -0
- data/lib/pdf_outline_editor/loader.rb +85 -0
- data/lib/pdf_outline_editor/runner.rb +56 -0
- data/lib/pdf_outline_editor/version.rb +3 -0
- data/vendor/pdfbox/pdfbox-app-2.0.13.jar +0 -0
- metadata +98 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: f4919cc4df58a6af4c74185a140a8845176b9afef34bed77558171361fbb299e
|
4
|
+
data.tar.gz: 3dd0368ac59022b051083b41b48dc48a21944e1d224d570574651d95298697a5
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 9e523afaa754c0b56534e34dd65688416d6e6b109770890f8bc19b0a7fff8ae586c828e9fe35a2245ea0164582ccb7e96d590a2afe3d8b260158cc27bfd5ad5e
|
7
|
+
data.tar.gz: 77fbe6d6d9d8afaf5bd4eb78aa987a857ef1690e99e6a72379eb487820526aa5e47779a25f30f3f3cd09ca63a3c1697517f0330e9053a79cd0505b0a3a445b84
|
data/README.md
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
# `pdf_outline_editor`
|
2
|
+
|
3
|
+
[](https://travis-ci.org/healthypackrat/pdf_outline_editor)
|
4
|
+
|
5
|
+
This gem provides a command to get/set PDF outlines from a JSON/YAML definition file.
|
6
|
+
|
7
|
+
## Requirements
|
8
|
+
|
9
|
+
- JRuby
|
10
|
+
|
11
|
+
## Installation
|
12
|
+
|
13
|
+
```
|
14
|
+
$ jgem install pdf_outline_editor
|
15
|
+
```
|
16
|
+
|
17
|
+
## Usage
|
18
|
+
|
19
|
+
First, generate outlines definition file by running `init` command:
|
20
|
+
|
21
|
+
```
|
22
|
+
$ pdf_outline_editor init -f json > toc.json
|
23
|
+
```
|
24
|
+
|
25
|
+
or, by running `dump` command with an existing pdf file:
|
26
|
+
|
27
|
+
```
|
28
|
+
$ pdf_outline_editor dump -f json input.pdf > toc.json
|
29
|
+
```
|
30
|
+
|
31
|
+
(Edit `toc.json` as you like...)
|
32
|
+
|
33
|
+
Then run `load` command to set outlines:
|
34
|
+
|
35
|
+
```
|
36
|
+
$ pdf_outline_editor load input.pdf toc.json output.pdf
|
37
|
+
```
|
38
|
+
|
39
|
+
## Development
|
40
|
+
|
41
|
+
Run `bin/jruby-ng-server` in a new terminal window for faster loading.
|
42
|
+
|
43
|
+
Then run `bin/rspec` to run the specs.
|
44
|
+
|
45
|
+
## Contributing
|
46
|
+
|
47
|
+
Bug reports and pull requests are welcome on GitHub at <https://github.com/healthypackrat/pdf_outline_editor>.
|
48
|
+
|
49
|
+
## License
|
50
|
+
|
51
|
+
The gem is available as open source under the terms of the [Apache License, Version 2.0](https://opensource.org/licenses/Apache-2.0).
|
@@ -0,0 +1,17 @@
|
|
1
|
+
require 'java'
|
2
|
+
|
3
|
+
require_relative '../vendor/pdfbox/pdfbox-app-2.0.13.jar'
|
4
|
+
|
5
|
+
require 'pdf_outline_editor/version'
|
6
|
+
|
7
|
+
require 'pdf_outline_editor/dumper'
|
8
|
+
require 'pdf_outline_editor/loader'
|
9
|
+
|
10
|
+
require 'pdf_outline_editor/runner'
|
11
|
+
require 'pdf_outline_editor/commands/dump_command'
|
12
|
+
require 'pdf_outline_editor/commands/init_command'
|
13
|
+
require 'pdf_outline_editor/commands/load_command'
|
14
|
+
|
15
|
+
module PdfOutlineEditor
|
16
|
+
class Error < StandardError; end
|
17
|
+
end
|
@@ -0,0 +1,68 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module PdfOutlineEditor
|
4
|
+
module Commands
|
5
|
+
class DumpCommand
|
6
|
+
attr_reader :output_format, :input_pdf_path
|
7
|
+
|
8
|
+
def initialize(argv)
|
9
|
+
@parser = nil
|
10
|
+
|
11
|
+
@output_formats = [:json, :yaml]
|
12
|
+
@output_format = :json
|
13
|
+
|
14
|
+
@input_pdf_path = nil
|
15
|
+
|
16
|
+
parser.parse!(argv)
|
17
|
+
|
18
|
+
handle_args(argv)
|
19
|
+
end
|
20
|
+
|
21
|
+
def run
|
22
|
+
Dumper.open(@input_pdf_path) do |dumper|
|
23
|
+
outlines = dumper.dump
|
24
|
+
|
25
|
+
if outlines
|
26
|
+
puts send("convert_to_#{@output_format}", outlines)
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
30
|
+
|
31
|
+
private
|
32
|
+
|
33
|
+
def parser
|
34
|
+
return @parser if @parser
|
35
|
+
|
36
|
+
@parser = OptionParser.new
|
37
|
+
|
38
|
+
@parser.banner = "Usage: #{File.basename($0)} dump [options] <input-pdf-path>"
|
39
|
+
|
40
|
+
desc = "Output format (default: #{@output_format}; one of #{@output_formats.join(', ')})"
|
41
|
+
@parser.on('-f', '--format=FORMAT', @output_formats, desc) do |value|
|
42
|
+
@output_format = value.to_sym
|
43
|
+
end
|
44
|
+
|
45
|
+
@parser
|
46
|
+
end
|
47
|
+
|
48
|
+
def handle_args(argv)
|
49
|
+
@input_pdf_path = argv.shift
|
50
|
+
raise Error, 'missing input pdf path' unless @input_pdf_path
|
51
|
+
end
|
52
|
+
|
53
|
+
def convert_to_json(outlines)
|
54
|
+
require 'json'
|
55
|
+
|
56
|
+
JSON.pretty_generate(outlines)
|
57
|
+
end
|
58
|
+
|
59
|
+
def convert_to_yaml(outlines)
|
60
|
+
require 'yaml'
|
61
|
+
|
62
|
+
YAML.dump(outlines)
|
63
|
+
end
|
64
|
+
|
65
|
+
Runner.register_command(:dump, self)
|
66
|
+
end
|
67
|
+
end
|
68
|
+
end
|
@@ -0,0 +1,70 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module PdfOutlineEditor
|
4
|
+
module Commands
|
5
|
+
class InitCommand
|
6
|
+
attr_reader :output_format
|
7
|
+
|
8
|
+
def initialize(argv)
|
9
|
+
@parser = nil
|
10
|
+
|
11
|
+
@output_formats = [:json, :yaml]
|
12
|
+
@output_format = :json
|
13
|
+
|
14
|
+
parser.parse!(argv)
|
15
|
+
end
|
16
|
+
|
17
|
+
def run
|
18
|
+
sample_outlines = [
|
19
|
+
{
|
20
|
+
'title' => 'Chapter 1',
|
21
|
+
'page' => 1,
|
22
|
+
'children' => [
|
23
|
+
{
|
24
|
+
'title' => 'Section 1.1',
|
25
|
+
'page' => 2
|
26
|
+
}
|
27
|
+
]
|
28
|
+
},
|
29
|
+
{
|
30
|
+
'title' => 'Chapter 2',
|
31
|
+
'page' => 3
|
32
|
+
}
|
33
|
+
]
|
34
|
+
|
35
|
+
puts send("convert_to_#{@output_format}", sample_outlines)
|
36
|
+
end
|
37
|
+
|
38
|
+
private
|
39
|
+
|
40
|
+
def parser
|
41
|
+
return @parser if @parser
|
42
|
+
|
43
|
+
@parser = OptionParser.new
|
44
|
+
|
45
|
+
@parser.banner = "Usage: #{File.basename($0)} init [options]"
|
46
|
+
|
47
|
+
desc = "Output format (default: #{@output_format}; one of #{@output_formats.join(', ')})"
|
48
|
+
@parser.on('-f', '--format=FORMAT', @output_formats, desc) do |value|
|
49
|
+
@output_format = value.to_sym
|
50
|
+
end
|
51
|
+
|
52
|
+
@parser
|
53
|
+
end
|
54
|
+
|
55
|
+
def convert_to_json(outlines)
|
56
|
+
require 'json'
|
57
|
+
|
58
|
+
JSON.pretty_generate(outlines)
|
59
|
+
end
|
60
|
+
|
61
|
+
def convert_to_yaml(outlines)
|
62
|
+
require 'yaml'
|
63
|
+
|
64
|
+
YAML.dump(outlines)
|
65
|
+
end
|
66
|
+
|
67
|
+
Runner.register_command(:init, self)
|
68
|
+
end
|
69
|
+
end
|
70
|
+
end
|
@@ -0,0 +1,80 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module PdfOutlineEditor
|
4
|
+
module Commands
|
5
|
+
class LoadCommand
|
6
|
+
def initialize(argv)
|
7
|
+
@parser = nil
|
8
|
+
|
9
|
+
@input_pdf_path = nil
|
10
|
+
@outlines = nil
|
11
|
+
@output_pdf_path = nil
|
12
|
+
|
13
|
+
parser.parse!(argv)
|
14
|
+
|
15
|
+
handle_args(argv)
|
16
|
+
end
|
17
|
+
|
18
|
+
def run
|
19
|
+
Loader.open(@input_pdf_path) do |loader|
|
20
|
+
loader.load(@outlines)
|
21
|
+
loader.save(@output_pdf_path)
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
private
|
26
|
+
|
27
|
+
def parser
|
28
|
+
return @parser if @parser
|
29
|
+
|
30
|
+
@parser = OptionParser.new
|
31
|
+
|
32
|
+
@parser.banner = "Usage: #{File.basename($0)} load <input-pdf-path> <input-outlines-path> <output-pdf-path>"
|
33
|
+
|
34
|
+
@parser
|
35
|
+
end
|
36
|
+
|
37
|
+
def handle_args(argv)
|
38
|
+
@input_pdf_path = argv.shift
|
39
|
+
raise Error, 'missing input pdf path' unless @input_pdf_path
|
40
|
+
|
41
|
+
input_outlines_path = argv.shift
|
42
|
+
raise Error, 'missing input outlines path' unless input_outlines_path
|
43
|
+
@outlines = parse_outlines(input_outlines_path)
|
44
|
+
|
45
|
+
@output_pdf_path = argv.shift
|
46
|
+
raise Error, 'missing output pdf path' unless @output_pdf_path
|
47
|
+
end
|
48
|
+
|
49
|
+
def parse_outlines(path)
|
50
|
+
ext = File.extname(path)[1..-1]
|
51
|
+
|
52
|
+
method_name = "parse_#{ext}_outlines"
|
53
|
+
|
54
|
+
if respond_to?(method_name, true)
|
55
|
+
send(method_name, path)
|
56
|
+
else
|
57
|
+
raise Error, "unknown extension: #{ext}"
|
58
|
+
end
|
59
|
+
end
|
60
|
+
|
61
|
+
def parse_json_outlines(path)
|
62
|
+
require 'json'
|
63
|
+
|
64
|
+
JSON.parse(File.read(path))
|
65
|
+
end
|
66
|
+
|
67
|
+
def parse_yaml_outlines(path)
|
68
|
+
require 'yaml'
|
69
|
+
|
70
|
+
YAML.load_file(path)
|
71
|
+
end
|
72
|
+
|
73
|
+
def parse_yml_outlines(path)
|
74
|
+
parse_yaml_outlines(path)
|
75
|
+
end
|
76
|
+
|
77
|
+
Runner.register_command(:load, self)
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
@@ -0,0 +1,74 @@
|
|
1
|
+
module PdfOutlineEditor
|
2
|
+
class Dumper
|
3
|
+
java_import org.apache.pdfbox.pdmodel.PDDocument
|
4
|
+
|
5
|
+
JavaFile = java.io.File
|
6
|
+
|
7
|
+
def self.open(input_pdf_path)
|
8
|
+
dumper = new(input_pdf_path)
|
9
|
+
|
10
|
+
begin
|
11
|
+
yield dumper
|
12
|
+
ensure
|
13
|
+
dumper.close
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
attr_reader :closed
|
18
|
+
|
19
|
+
def initialize(input_pdf_path)
|
20
|
+
begin
|
21
|
+
@doc = PDDocument.load(JavaFile.new(input_pdf_path))
|
22
|
+
rescue
|
23
|
+
raise Error, $!.message
|
24
|
+
end
|
25
|
+
|
26
|
+
@pages = @doc.pages
|
27
|
+
|
28
|
+
@closed = false
|
29
|
+
end
|
30
|
+
|
31
|
+
def dump
|
32
|
+
root_outline = @doc.document_catalog.document_outline
|
33
|
+
|
34
|
+
if root_outline
|
35
|
+
traverse(root_outline)
|
36
|
+
else
|
37
|
+
nil
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def close
|
42
|
+
unless @closed
|
43
|
+
@doc.close
|
44
|
+
@closed = true
|
45
|
+
end
|
46
|
+
end
|
47
|
+
|
48
|
+
private
|
49
|
+
|
50
|
+
def traverse(outline)
|
51
|
+
outline_items = []
|
52
|
+
|
53
|
+
current = outline.first_child
|
54
|
+
|
55
|
+
while current
|
56
|
+
outline_item = {}
|
57
|
+
|
58
|
+
outline_item['title'] = current.title
|
59
|
+
|
60
|
+
page = current.find_destination_page(@doc)
|
61
|
+
outline_item['page'] = @pages.index_of(page) + 1
|
62
|
+
|
63
|
+
children = traverse(current)
|
64
|
+
outline_item['children'] = children unless children.empty?
|
65
|
+
|
66
|
+
outline_items << outline_item
|
67
|
+
|
68
|
+
current = current.next_sibling
|
69
|
+
end
|
70
|
+
|
71
|
+
outline_items
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module PdfOutlineEditor
|
2
|
+
class Loader
|
3
|
+
java_import org.apache.pdfbox.pdmodel.PDDocument
|
4
|
+
java_import org.apache.pdfbox.pdmodel.interactive.documentnavigation.destination.PDPageXYZDestination
|
5
|
+
java_import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDDocumentOutline
|
6
|
+
java_import org.apache.pdfbox.pdmodel.interactive.documentnavigation.outline.PDOutlineItem
|
7
|
+
|
8
|
+
JavaFile = java.io.File
|
9
|
+
|
10
|
+
def self.open(input_pdf_path)
|
11
|
+
loader = new(input_pdf_path)
|
12
|
+
|
13
|
+
begin
|
14
|
+
yield loader
|
15
|
+
ensure
|
16
|
+
loader.close
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
attr_reader :closed
|
21
|
+
|
22
|
+
def initialize(input_pdf_path)
|
23
|
+
begin
|
24
|
+
@doc = PDDocument.load(JavaFile.new(input_pdf_path))
|
25
|
+
rescue
|
26
|
+
raise Error, $!.message
|
27
|
+
end
|
28
|
+
|
29
|
+
@pages = @doc.pages.to_a
|
30
|
+
|
31
|
+
@closed = false
|
32
|
+
end
|
33
|
+
|
34
|
+
def load(entries)
|
35
|
+
root_outline = PDDocumentOutline.new
|
36
|
+
|
37
|
+
@doc.document_catalog.document_outline = root_outline
|
38
|
+
|
39
|
+
entries.each do |entry|
|
40
|
+
set_outline(root_outline, entry)
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def save(output_pdf_path)
|
45
|
+
@doc.save(output_pdf_path)
|
46
|
+
end
|
47
|
+
|
48
|
+
def close
|
49
|
+
unless @closed
|
50
|
+
@doc.close
|
51
|
+
@closed = true
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
private
|
56
|
+
|
57
|
+
def set_outline(parent_outline, entry)
|
58
|
+
page_number = entry.fetch('page')
|
59
|
+
|
60
|
+
max_page_number = @pages.size
|
61
|
+
|
62
|
+
unless (1..max_page_number).include?(page_number)
|
63
|
+
raise Error, "page number must be between 1 and #{max_page_number}: got #{page_number}"
|
64
|
+
end
|
65
|
+
|
66
|
+
page = @pages[page_number - 1]
|
67
|
+
|
68
|
+
dest = PDPageXYZDestination.new
|
69
|
+
dest.page = page
|
70
|
+
dest.top = page.bbox.upper_right_y
|
71
|
+
dest.left = 0
|
72
|
+
dest.zoom = -1
|
73
|
+
|
74
|
+
outline = PDOutlineItem.new
|
75
|
+
outline.destination = dest
|
76
|
+
outline.title = entry.fetch('title')
|
77
|
+
|
78
|
+
entry.fetch('children', []).each do |child|
|
79
|
+
set_outline(outline, child)
|
80
|
+
end
|
81
|
+
|
82
|
+
parent_outline.add_last(outline)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
@@ -0,0 +1,56 @@
|
|
1
|
+
require 'optparse'
|
2
|
+
|
3
|
+
module PdfOutlineEditor
|
4
|
+
class Runner
|
5
|
+
class << self
|
6
|
+
_known_commands = {}
|
7
|
+
|
8
|
+
define_method :known_commands do
|
9
|
+
_known_commands
|
10
|
+
end
|
11
|
+
|
12
|
+
define_method :register_command do |key, klass|
|
13
|
+
_known_commands[key] = klass
|
14
|
+
end
|
15
|
+
end
|
16
|
+
|
17
|
+
def initialize(argv)
|
18
|
+
@argv = argv
|
19
|
+
|
20
|
+
@parser = nil
|
21
|
+
|
22
|
+
parser.order!(@argv)
|
23
|
+
end
|
24
|
+
|
25
|
+
def run
|
26
|
+
if @argv.empty?
|
27
|
+
raise Error, "missing a command: available commands are #{Runner.known_commands.keys.sort.join(', ')}"
|
28
|
+
end
|
29
|
+
|
30
|
+
command_name = @argv.shift
|
31
|
+
|
32
|
+
command_class = Runner.known_commands[command_name.to_sym]
|
33
|
+
|
34
|
+
if command_class
|
35
|
+
command = command_class.new(@argv)
|
36
|
+
command.run
|
37
|
+
else
|
38
|
+
raise Error, "unknown command: #{command_name}"
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
private
|
43
|
+
|
44
|
+
def parser
|
45
|
+
return @parser if @parser
|
46
|
+
|
47
|
+
@parser = OptionParser.new
|
48
|
+
|
49
|
+
@parser.banner = "Usage: #{File.basename($0)} <command> <args>"
|
50
|
+
|
51
|
+
@parser.version = VERSION
|
52
|
+
|
53
|
+
@parser
|
54
|
+
end
|
55
|
+
end
|
56
|
+
end
|
Binary file
|
metadata
ADDED
@@ -0,0 +1,98 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: pdf_outline_editor
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: java
|
6
|
+
authors:
|
7
|
+
- healthypackrat
|
8
|
+
autorequire:
|
9
|
+
bindir: exe
|
10
|
+
cert_chain: []
|
11
|
+
date: 2019-03-31 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
requirement: !ruby/object:Gem::Requirement
|
15
|
+
requirements:
|
16
|
+
- - "~>"
|
17
|
+
- !ruby/object:Gem::Version
|
18
|
+
version: '2.0'
|
19
|
+
name: bundler
|
20
|
+
prerelease: false
|
21
|
+
type: :development
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '2.0'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
requirement: !ruby/object:Gem::Requirement
|
29
|
+
requirements:
|
30
|
+
- - "~>"
|
31
|
+
- !ruby/object:Gem::Version
|
32
|
+
version: '10.0'
|
33
|
+
name: rake
|
34
|
+
prerelease: false
|
35
|
+
type: :development
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
requirement: !ruby/object:Gem::Requirement
|
43
|
+
requirements:
|
44
|
+
- - "~>"
|
45
|
+
- !ruby/object:Gem::Version
|
46
|
+
version: '3.0'
|
47
|
+
name: rspec
|
48
|
+
prerelease: false
|
49
|
+
type: :development
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description:
|
56
|
+
email:
|
57
|
+
- healthypackrat@gmail.com
|
58
|
+
executables:
|
59
|
+
- pdf_outline_editor
|
60
|
+
extensions: []
|
61
|
+
extra_rdoc_files: []
|
62
|
+
files:
|
63
|
+
- README.md
|
64
|
+
- exe/pdf_outline_editor
|
65
|
+
- lib/pdf_outline_editor.rb
|
66
|
+
- lib/pdf_outline_editor/commands/dump_command.rb
|
67
|
+
- lib/pdf_outline_editor/commands/init_command.rb
|
68
|
+
- lib/pdf_outline_editor/commands/load_command.rb
|
69
|
+
- lib/pdf_outline_editor/dumper.rb
|
70
|
+
- lib/pdf_outline_editor/loader.rb
|
71
|
+
- lib/pdf_outline_editor/runner.rb
|
72
|
+
- lib/pdf_outline_editor/version.rb
|
73
|
+
- vendor/pdfbox/pdfbox-app-2.0.13.jar
|
74
|
+
homepage: https://github.com/healthypackrat/pdf_outline_editor
|
75
|
+
licenses:
|
76
|
+
- Apache-2.0
|
77
|
+
metadata: {}
|
78
|
+
post_install_message:
|
79
|
+
rdoc_options: []
|
80
|
+
require_paths:
|
81
|
+
- lib
|
82
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
83
|
+
requirements:
|
84
|
+
- - ">="
|
85
|
+
- !ruby/object:Gem::Version
|
86
|
+
version: '0'
|
87
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
88
|
+
requirements:
|
89
|
+
- - ">="
|
90
|
+
- !ruby/object:Gem::Version
|
91
|
+
version: '0'
|
92
|
+
requirements: []
|
93
|
+
rubyforge_project:
|
94
|
+
rubygems_version: 2.7.6
|
95
|
+
signing_key:
|
96
|
+
specification_version: 4
|
97
|
+
summary: Set PDF outlines from a JSON/YAML definition file
|
98
|
+
test_files: []
|