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.
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: []