pd4ml 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.
- checksums.yaml +7 -0
- data/README.md +91 -0
- data/docs/api.md +546 -0
- data/docs/guide.md +782 -0
- data/exe/pd4ml +132 -0
- data/lib/pd4ml/bridge.rb +362 -0
- data/lib/pd4ml/errors.rb +42 -0
- data/lib/pd4ml/installer.rb +183 -0
- data/lib/pd4ml/java.rb +209 -0
- data/lib/pd4ml/pd4ml-bridge.jar +0 -0
- data/lib/pd4ml/pd4ml.rb +184 -0
- data/lib/pd4ml/version.rb +5 -0
- data/lib/pd4ml.rb +169 -0
- metadata +58 -0
data/lib/pd4ml.rb
ADDED
|
@@ -0,0 +1,169 @@
|
|
|
1
|
+
# frozen_string_literal: true
|
|
2
|
+
|
|
3
|
+
require 'fileutils'
|
|
4
|
+
require 'pathname'
|
|
5
|
+
require 'uri'
|
|
6
|
+
require_relative 'pd4ml/version'
|
|
7
|
+
require_relative 'pd4ml/errors'
|
|
8
|
+
require_relative 'pd4ml/bridge'
|
|
9
|
+
require_relative 'pd4ml/java'
|
|
10
|
+
require_relative 'pd4ml/installer'
|
|
11
|
+
require_relative 'pd4ml/pd4ml'
|
|
12
|
+
|
|
13
|
+
# PD4ML for Ruby: HTML and CSS to PDF, PDF/A, PDF/UA, DOCX, RTF and images, with the full public
|
|
14
|
+
# PD4ML API (Java package com.pd4ml). PD4ML runs in a Java bridge process started on first use.
|
|
15
|
+
#
|
|
16
|
+
# require 'pd4ml'
|
|
17
|
+
#
|
|
18
|
+
# pd = Pd4ml::PD4ML.new # the v42 layout engine
|
|
19
|
+
# pd.set_page_size(Pd4ml::PageSize::A4)
|
|
20
|
+
# pd.read_html_string('<h1>Hello</h1>')
|
|
21
|
+
# pd.write_pdf('hello.pdf')
|
|
22
|
+
module Pd4ml
|
|
23
|
+
# the public PD4ML classes: constants, static methods, constructors
|
|
24
|
+
Constants = Java.type('com.pd4ml.Constants')
|
|
25
|
+
LayoutEngine = Java.type('com.pd4ml.Constants$LayoutEngine')
|
|
26
|
+
ErrorPolicy = Java.type('com.pd4ml.Constants$ErrorPolicy')
|
|
27
|
+
PageSize = Java.type('com.pd4ml.PageSize')
|
|
28
|
+
PageMargins = Java.type('com.pd4ml.PageMargins')
|
|
29
|
+
Dimensions = Java.type('com.pd4ml.Dimensions')
|
|
30
|
+
Units = Java.type('com.pd4ml.Dimensions$Units')
|
|
31
|
+
PdfSpec = Java.type('com.pd4ml.PdfSpec')
|
|
32
|
+
PdfDocument = Java.type('com.pd4ml.PdfDocument')
|
|
33
|
+
ProgressListener = Java.type('com.pd4ml.ProgressListener')
|
|
34
|
+
StatusMessage = Java.type('com.pd4ml.StatusMessage')
|
|
35
|
+
ResourceProvider = Java.type('com.pd4ml.ResourceProvider')
|
|
36
|
+
CustomTag = Java.type('com.pd4ml.CustomTag')
|
|
37
|
+
|
|
38
|
+
FORMATS = %w[PDF PDFA PDFUA].freeze
|
|
39
|
+
|
|
40
|
+
class << self
|
|
41
|
+
# The PD4ML (Java) version.
|
|
42
|
+
def version = Java.type('com.pd4ml.PD4ML').getVersion.to_s
|
|
43
|
+
|
|
44
|
+
# Whether the PD4ML build chooses between layout engines (Constants.LayoutEngine, from 4.2):
|
|
45
|
+
# earlier builds, the published 4.1.x among them, have one engine only.
|
|
46
|
+
def layout_engines?
|
|
47
|
+
bridge = Bridge.get
|
|
48
|
+
unless @engines_bridge.equal?(bridge)
|
|
49
|
+
@engines = begin
|
|
50
|
+
bridge.get_field('com.pd4ml.Constants$LayoutEngine', 'v42')
|
|
51
|
+
true
|
|
52
|
+
rescue JavaError
|
|
53
|
+
false
|
|
54
|
+
end
|
|
55
|
+
@engines_bridge = bridge
|
|
56
|
+
end
|
|
57
|
+
@engines
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
# Sets up the bridge before first use (Bridge.configure).
|
|
61
|
+
def configure(**options) = Bridge.configure(**options)
|
|
62
|
+
|
|
63
|
+
# Stops the bridge (it starts again on the next use).
|
|
64
|
+
def shutdown = Bridge.shutdown
|
|
65
|
+
|
|
66
|
+
# Downloads a PD4ML build (Installer.install).
|
|
67
|
+
def install(...) = Installer.install(...)
|
|
68
|
+
|
|
69
|
+
def installed_jar(...) = Installer.installed_jar(...)
|
|
70
|
+
def installed_classpath(...) = Installer.installed_classpath(...)
|
|
71
|
+
def installed_version(...) = Installer.installed_version(...)
|
|
72
|
+
def available_versions(...) = Installer.available_versions(...)
|
|
73
|
+
|
|
74
|
+
# A Java URL for a URL string, a URI, or a local path (relative: to the working directory).
|
|
75
|
+
def to_url(location)
|
|
76
|
+
return location if location.is_a?(JavaObject)
|
|
77
|
+
|
|
78
|
+
s = location.to_s
|
|
79
|
+
if s.match?(%r{\A[A-Za-z][A-Za-z0-9+.-]*://|\A(file|jar|data):}i) && !s.match?(%r{\A[A-Za-z]:[\\/]})
|
|
80
|
+
Java.type('java.net.URL').new(s)
|
|
81
|
+
else
|
|
82
|
+
Java.type('java.io.File').new(File.expand_path(s)).toURI.toURL
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# The PdfSpec for one of its keywords ('pdf/a-3b', case-insensitive); a PdfSpec, nil and the
|
|
87
|
+
# format names 'PDF', 'PDFA', 'PDFUA' as they are. Raises ArgumentError for an unknown
|
|
88
|
+
# keyword (PdfSpec.getInstance alone falls back to PDF 1.7 for it).
|
|
89
|
+
def pdf_spec(spec)
|
|
90
|
+
return spec unless spec.is_a?(String) || spec.is_a?(Symbol)
|
|
91
|
+
|
|
92
|
+
s = spec.to_s
|
|
93
|
+
return s if FORMATS.include?(s.upcase)
|
|
94
|
+
|
|
95
|
+
keywords = PdfSpec.list_keywords.to_s.scan(/'([^']+)'/).flatten
|
|
96
|
+
raise ArgumentError, "unknown PDF spec '#{s}'; one of: #{keywords.join(', ')}" unless keywords.any? { |k| k.casecmp?(s) }
|
|
97
|
+
|
|
98
|
+
PdfSpec.get_instance(s)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
# Converts one document to PDF: `source` as for PD4ML#read_html, `target` as for
|
|
102
|
+
# PD4ML#write_pdf. Options: base_url, page_size, page_margins, spec, engine, html_width.
|
|
103
|
+
def html_to_pdf(source, target = nil, base_url: nil, page_size: nil, page_margins: nil, spec: nil, engine: nil,
|
|
104
|
+
html_width: nil)
|
|
105
|
+
pd = PD4ML.new(engine: engine, html_width: html_width)
|
|
106
|
+
pd.setPageSize(page_size) if page_size
|
|
107
|
+
pd.setPageMargins(page_margins) if page_margins
|
|
108
|
+
pd.read_html(source, base_url)
|
|
109
|
+
pd.write_pdf(target, spec: spec)
|
|
110
|
+
end
|
|
111
|
+
|
|
112
|
+
# A com.pd4ml.PdfDocument from a path, URL, binary String/IO (+ password).
|
|
113
|
+
def open_pdf(source, password = nil)
|
|
114
|
+
if (source.is_a?(String) && source.match?(%r{\A[A-Za-z][A-Za-z0-9+.-]*://})) || source.is_a?(URI::Generic)
|
|
115
|
+
return PdfDocument.new(to_url(source), password)
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
PdfDocument.new(pdf_bytes(source), password)
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
# Writes a PdfDocument (after append, overlay...): returned as a binary String, or written to
|
|
122
|
+
# a path or IO. password: encrypts, with `permissions` (Constants flags; default
|
|
123
|
+
# Constants::DefaultPermissions).
|
|
124
|
+
def write_pdf(document, target = nil, password: nil, permissions: nil)
|
|
125
|
+
outs = []
|
|
126
|
+
if password
|
|
127
|
+
permissions ||= Constants::DefaultPermissions
|
|
128
|
+
Bridge.get.call(document, 'write', [Output.new(0), password, permissions], outs)
|
|
129
|
+
else
|
|
130
|
+
Bridge.get.call(document, 'write', [Output.new(0)], outs)
|
|
131
|
+
end
|
|
132
|
+
deliver(outs[0] || ''.b, target)
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
# PdfDocument.mergePDFs: two PDF documents appended into one.
|
|
136
|
+
def merge_pdfs(first, second, target = nil)
|
|
137
|
+
outs = []
|
|
138
|
+
Bridge.get.call_static('com.pd4ml.PdfDocument', 'mergePDFs', [pdf_bytes(first), pdf_bytes(second), Output.new(0)], outs)
|
|
139
|
+
deliver(outs[0] || ''.b, target)
|
|
140
|
+
end
|
|
141
|
+
|
|
142
|
+
# internal: writes data to a path or IO, or returns it for a nil target
|
|
143
|
+
def deliver(data, target)
|
|
144
|
+
return data if target.nil?
|
|
145
|
+
|
|
146
|
+
if target.respond_to?(:write) && !target.is_a?(String) && !target.is_a?(Pathname)
|
|
147
|
+
target.write(data)
|
|
148
|
+
else
|
|
149
|
+
File.binwrite(target.to_s, data)
|
|
150
|
+
end
|
|
151
|
+
nil
|
|
152
|
+
end
|
|
153
|
+
|
|
154
|
+
# internal: the content of a String/IO as a binary String (sent to Java as byte[])
|
|
155
|
+
def binary(source)
|
|
156
|
+
data = source.respond_to?(:read) ? source.read : source.to_s
|
|
157
|
+
data.b
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
private
|
|
161
|
+
|
|
162
|
+
def pdf_bytes(source)
|
|
163
|
+
return binary(source) if source.respond_to?(:read)
|
|
164
|
+
|
|
165
|
+
s = source.to_s
|
|
166
|
+
s.start_with?('%PDF') ? s.b : File.binread(s)
|
|
167
|
+
end
|
|
168
|
+
end
|
|
169
|
+
end
|
metadata
ADDED
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
|
2
|
+
name: pd4ml
|
|
3
|
+
version: !ruby/object:Gem::Version
|
|
4
|
+
version: 1.0.0
|
|
5
|
+
platform: ruby
|
|
6
|
+
authors:
|
|
7
|
+
- PD4ML
|
|
8
|
+
bindir: exe
|
|
9
|
+
cert_chain: []
|
|
10
|
+
date: 1980-01-02 00:00:00.000000000 Z
|
|
11
|
+
dependencies: []
|
|
12
|
+
description: The full public PD4ML API in Ruby. PD4ML runs in a Java bridge process;
|
|
13
|
+
the most recent PD4ML build is downloaded on first use.
|
|
14
|
+
email:
|
|
15
|
+
- support@pd4ml.com
|
|
16
|
+
executables:
|
|
17
|
+
- pd4ml
|
|
18
|
+
extensions: []
|
|
19
|
+
extra_rdoc_files: []
|
|
20
|
+
files:
|
|
21
|
+
- README.md
|
|
22
|
+
- docs/api.md
|
|
23
|
+
- docs/guide.md
|
|
24
|
+
- exe/pd4ml
|
|
25
|
+
- lib/pd4ml.rb
|
|
26
|
+
- lib/pd4ml/bridge.rb
|
|
27
|
+
- lib/pd4ml/errors.rb
|
|
28
|
+
- lib/pd4ml/installer.rb
|
|
29
|
+
- lib/pd4ml/java.rb
|
|
30
|
+
- lib/pd4ml/pd4ml-bridge.jar
|
|
31
|
+
- lib/pd4ml/pd4ml.rb
|
|
32
|
+
- lib/pd4ml/version.rb
|
|
33
|
+
homepage: https://github.com/zxfr/pd4ml-ruby
|
|
34
|
+
licenses:
|
|
35
|
+
- Nonstandard
|
|
36
|
+
metadata:
|
|
37
|
+
homepage_uri: https://github.com/zxfr/pd4ml-ruby
|
|
38
|
+
documentation_uri: https://pd4ml.com/docs/
|
|
39
|
+
rubygems_mfa_required: 'true'
|
|
40
|
+
rdoc_options: []
|
|
41
|
+
require_paths:
|
|
42
|
+
- lib
|
|
43
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
|
44
|
+
requirements:
|
|
45
|
+
- - ">="
|
|
46
|
+
- !ruby/object:Gem::Version
|
|
47
|
+
version: '3.1'
|
|
48
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
49
|
+
requirements:
|
|
50
|
+
- - ">="
|
|
51
|
+
- !ruby/object:Gem::Version
|
|
52
|
+
version: '0'
|
|
53
|
+
requirements: []
|
|
54
|
+
rubygems_version: 3.6.9
|
|
55
|
+
specification_version: 4
|
|
56
|
+
summary: 'PD4ML for Ruby: HTML and CSS to PDF, PDF/A, PDF/UA, ZUGFeRD, DOCX, RTF and
|
|
57
|
+
images'
|
|
58
|
+
test_files: []
|