pdf_oxide 0.3.55

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.
@@ -0,0 +1,97 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PdfOxide
4
+ # PDF/A · PDF/X · PDF/UA compliance validation (v0.3.50).
5
+ #
6
+ # Mirrors `fyi.oxide.pdf.PdfValidator`. Stateless façade.
7
+ #
8
+ # @example
9
+ # PdfOxide::PdfDocument.open('compliant.pdf') do |doc|
10
+ # puts PdfOxide::PdfValidator.pdf_a?(doc, level: :a1b)
11
+ # end
12
+ module PdfValidator
13
+ module_function
14
+
15
+ # PDF/A level → cdylib wire-format integer.
16
+ #
17
+ # Matches `src/ffi.rs:1225` (`0=A1b 1=A1a 2=A2b 3=A2a 4=A2u 5=A3b
18
+ # 6=A3a 7=A3u`). Every binding (Java, Ruby, PHP, C#, Go) sends the
19
+ # SAME integer for the same PDF/A level — the "B before A"
20
+ # intra-level order is the cdylib's contract, not a Ruby choice.
21
+ PDF_A_LEVELS = { a1b: 0, a1a: 1, a2b: 2, a2a: 3, a2u: 4, a3b: 5, a3a: 6, a3u: 7 }.freeze
22
+
23
+ # PDF/UA level → cdylib wire-format integer.
24
+ #
25
+ # Matches `src/ffi.rs:5538` (`level == 2 → UA-2, else UA-1`).
26
+ # 1-indexed, not 0-indexed; mirrors the C# `PdfUaLevel` enum.
27
+ PDF_UA_LEVELS = { ua1: 1, ua2: 2 }.freeze
28
+
29
+ # @return [Boolean] PDF/A compliance for `level`.
30
+ def pdf_a?(doc, level: :a1b)
31
+ raise ::PdfOxide::ArgumentError, 'doc cannot be nil' if doc.nil?
32
+
33
+ ordinal = PDF_A_LEVELS.fetch(level) do
34
+ raise ::PdfOxide::ArgumentError, "unknown PDF/A level: #{level.inspect}"
35
+ end
36
+ # If the native symbol is absent (older cdylib), surface a clean
37
+ # "unavailable" verdict instead of reading an uninitialised err
38
+ # buffer and raising a spurious ComplianceError.
39
+ return false unless Bindings.respond_to?(:pdf_validate_pdf_a_level)
40
+
41
+ err = ::FFI::MemoryPointer.new(:int32)
42
+ result_ptr = Bindings.pdf_validate_pdf_a_level(doc.handle, ordinal, err)
43
+ code = err.read_int32
44
+ raise ComplianceError, "pdf_validate_pdf_a_level failed (#{code})" if code != 0
45
+
46
+ compliance_verdict(result_ptr, :pdf_pdf_a_is_compliant, :pdf_pdf_a_results_free)
47
+ rescue ::FFI::NotFoundError
48
+ false
49
+ end
50
+
51
+ # @return [Boolean] PDF/UA compliance for `level`.
52
+ def pdf_ua?(doc, level: :ua1)
53
+ raise ::PdfOxide::ArgumentError, 'doc cannot be nil' if doc.nil?
54
+
55
+ ordinal = PDF_UA_LEVELS.fetch(level) do
56
+ raise ::PdfOxide::ArgumentError, "unknown PDF/UA level: #{level.inspect}"
57
+ end
58
+ err = ::FFI::MemoryPointer.new(:int32)
59
+ result_ptr = Bindings.pdf_validate_pdf_ua(doc.handle, ordinal, err)
60
+ code = err.read_int32
61
+ raise ComplianceError, "pdf_validate_pdf_ua failed (#{code})" if code != 0
62
+
63
+ compliance_verdict(result_ptr, :pdf_pdf_ua_is_accessible, :pdf_pdf_ua_results_free)
64
+ rescue ::FFI::NotFoundError
65
+ false
66
+ end
67
+
68
+ # @return [Hash] simplified PDF/A validation result: { compliant:, violations: }.
69
+ def validate_pdf_a(doc, level: :a1b)
70
+ { compliant: pdf_a?(doc, level: level), violations: [] }
71
+ end
72
+
73
+ # @return [Hash] simplified PDF/UA validation result.
74
+ def validate_pdf_ua(doc, level: :ua1)
75
+ { compliant: pdf_ua?(doc, level: level), violations: [] }
76
+ end
77
+
78
+ # The accessor symbols (pdf_pdf_a_is_compliant, pdf_pdf_x_is_compliant,
79
+ # pdf_pdf_ua_is_accessible) all take (results, int32_t *error_code).
80
+ # Pre-v0.3.55 Ruby bound them with just (results) — register garbage
81
+ # was used as the err pointer and the cdylib wrote through it,
82
+ # producing the same flaky segfault class as the search-result
83
+ # accessors (#547). Both args are passed here so the new 2-arg
84
+ # binding is honoured.
85
+ def self.compliance_verdict(result_ptr, accessor_sym, free_sym)
86
+ return false if result_ptr.nil? || result_ptr.null?
87
+
88
+ err = ::FFI::MemoryPointer.new(:int32)
89
+ begin
90
+ Bindings.send(accessor_sym, result_ptr, err)
91
+ ensure
92
+ Bindings.send(free_sym, result_ptr) if Bindings.respond_to?(free_sym)
93
+ end
94
+ end
95
+ private_class_method :compliance_verdict
96
+ end
97
+ end
@@ -0,0 +1,5 @@
1
+ # frozen_string_literal: true
2
+
3
+ module PdfOxide
4
+ VERSION = '0.3.55'
5
+ end
data/lib/pdf_oxide.rb ADDED
@@ -0,0 +1,60 @@
1
+ # frozen_string_literal: true
2
+
3
+ # Ruby bindings for pdf_oxide — high-performance PDF processing.
4
+ #
5
+ # Idiomatic 9-class API mirroring the Java binding's shape at
6
+ # `fyi.oxide.pdf.*`. All native calls route through the FFI layer
7
+ # at `PdfOxide::FFI::Bindings`; UTF-8 marshalling is via
8
+ # `PdfOxide::FFI::StringMarshaller`.
9
+ #
10
+ # Public surface:
11
+ # - {PdfOxide::PdfDocument} — read-only entry point.
12
+ # - {PdfOxide::PdfPage} — per-page view.
13
+ # - {PdfOxide::Pdf} — create + transform (markdown/html/text → PDF).
14
+ # - {PdfOxide::DocumentEditor} — write-side: form-fill, redaction, save.
15
+ # - {PdfOxide::AutoExtractor} — typed-reason auto-extraction (#519).
16
+ # - {PdfOxide::MarkdownConverter} — PDF → Markdown / HTML.
17
+ # - {PdfOxide::PdfValidator} — PDF/A · PDF/UA compliance.
18
+ # - {PdfOxide::PdfSigner} — PAdES B/T/LT/LTA signing.
19
+ # - {PdfOxide::PdfPolicy} — process-global crypto-governance.
20
+
21
+ require 'ffi'
22
+
23
+ require_relative 'pdf_oxide/version'
24
+ require_relative 'pdf_oxide/errors'
25
+ require_relative 'pdf_oxide/ffi/library'
26
+ require_relative 'pdf_oxide/ffi/bindings'
27
+ require_relative 'pdf_oxide/ffi/string_marshaller'
28
+
29
+ module PdfOxide
30
+ # Convenience constants reaching into the FFI sub-module. Keeps
31
+ # downstream callers free of the `PdfOxide::FFI::` prefix when
32
+ # accessing the binding layer; matches the Java binding's flat shape.
33
+ Bindings = FFI::Bindings
34
+ StringMarshaller = FFI::StringMarshaller
35
+ end
36
+
37
+ require_relative 'pdf_oxide/pdf_page'
38
+ require_relative 'pdf_oxide/markdown_converter'
39
+ require_relative 'pdf_oxide/auto_extractor'
40
+ require_relative 'pdf_oxide/pdf_document'
41
+ require_relative 'pdf_oxide/pdf'
42
+ require_relative 'pdf_oxide/document_editor'
43
+ require_relative 'pdf_oxide/pdf_signer'
44
+ require_relative 'pdf_oxide/pdf_validator'
45
+ require_relative 'pdf_oxide/pdf_policy'
46
+
47
+ module PdfOxide
48
+ class << self
49
+ # Open a PDF for reading.
50
+ # @return [PdfDocument]
51
+ def open(source, password: nil, &block)
52
+ PdfDocument.open(source, password: password, &block)
53
+ end
54
+
55
+ # @return [String] library version.
56
+ def version
57
+ VERSION
58
+ end
59
+ end
60
+ end
metadata ADDED
@@ -0,0 +1,197 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pdf_oxide
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.3.55
5
+ platform: ruby
6
+ authors:
7
+ - PDF Oxide Contributors
8
+ autorequire:
9
+ bindir: bin
10
+ cert_chain: []
11
+ date: 2026-05-25 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: ffi
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :runtime
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: bundler
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '2.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '2.0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '13.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '13.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.12'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.12'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '1.86'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '1.86'
83
+ - !ruby/object:Gem::Dependency
84
+ name: rubocop-rspec
85
+ requirement: !ruby/object:Gem::Requirement
86
+ requirements:
87
+ - - "~>"
88
+ - !ruby/object:Gem::Version
89
+ version: '2.20'
90
+ type: :development
91
+ prerelease: false
92
+ version_requirements: !ruby/object:Gem::Requirement
93
+ requirements:
94
+ - - "~>"
95
+ - !ruby/object:Gem::Version
96
+ version: '2.20'
97
+ - !ruby/object:Gem::Dependency
98
+ name: simplecov-lcov
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: '0.8'
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: '0.8'
111
+ - !ruby/object:Gem::Dependency
112
+ name: yard
113
+ requirement: !ruby/object:Gem::Requirement
114
+ requirements:
115
+ - - "~>"
116
+ - !ruby/object:Gem::Version
117
+ version: '0.9'
118
+ type: :development
119
+ prerelease: false
120
+ version_requirements: !ruby/object:Gem::Requirement
121
+ requirements:
122
+ - - "~>"
123
+ - !ruby/object:Gem::Version
124
+ version: '0.9'
125
+ - !ruby/object:Gem::Dependency
126
+ name: simplecov
127
+ requirement: !ruby/object:Gem::Requirement
128
+ requirements:
129
+ - - "~>"
130
+ - !ruby/object:Gem::Version
131
+ version: '0.22'
132
+ type: :development
133
+ prerelease: false
134
+ version_requirements: !ruby/object:Gem::Requirement
135
+ requirements:
136
+ - - "~>"
137
+ - !ruby/object:Gem::Version
138
+ version: '0.22'
139
+ description: Idiomatic Ruby bindings for PDF Oxide. Process, analyze, and generate
140
+ PDFs through the libpdf_oxide cdylib used by the Python, Java, Node, Go, and C#
141
+ bindings.
142
+ email:
143
+ - support@pdf-oxide.dev
144
+ executables: []
145
+ extensions: []
146
+ extra_rdoc_files: []
147
+ files:
148
+ - Gemfile
149
+ - LICENSE
150
+ - LICENSE-APACHE
151
+ - LICENSE-MIT
152
+ - README.md
153
+ - lib/pdf_oxide.rb
154
+ - lib/pdf_oxide/auto_extractor.rb
155
+ - lib/pdf_oxide/document_editor.rb
156
+ - lib/pdf_oxide/errors.rb
157
+ - lib/pdf_oxide/ffi/bindings.rb
158
+ - lib/pdf_oxide/ffi/library.rb
159
+ - lib/pdf_oxide/ffi/string_marshaller.rb
160
+ - lib/pdf_oxide/markdown_converter.rb
161
+ - lib/pdf_oxide/pdf.rb
162
+ - lib/pdf_oxide/pdf_document.rb
163
+ - lib/pdf_oxide/pdf_page.rb
164
+ - lib/pdf_oxide/pdf_policy.rb
165
+ - lib/pdf_oxide/pdf_signer.rb
166
+ - lib/pdf_oxide/pdf_validator.rb
167
+ - lib/pdf_oxide/version.rb
168
+ homepage: https://github.com/yfedoseev/pdf_oxide
169
+ licenses:
170
+ - MIT
171
+ - Apache-2.0
172
+ metadata:
173
+ homepage_uri: https://github.com/yfedoseev/pdf_oxide
174
+ source_code_uri: https://github.com/yfedoseev/pdf_oxide
175
+ bug_tracker_uri: https://github.com/yfedoseev/pdf_oxide/issues
176
+ documentation_uri: https://rubydoc.info/gems/pdf_oxide
177
+ changelog_uri: https://github.com/yfedoseev/pdf_oxide/blob/main/CHANGELOG.md
178
+ post_install_message:
179
+ rdoc_options: []
180
+ require_paths:
181
+ - lib
182
+ required_ruby_version: !ruby/object:Gem::Requirement
183
+ requirements:
184
+ - - ">="
185
+ - !ruby/object:Gem::Version
186
+ version: 3.1.0
187
+ required_rubygems_version: !ruby/object:Gem::Requirement
188
+ requirements:
189
+ - - ">="
190
+ - !ruby/object:Gem::Version
191
+ version: '0'
192
+ requirements: []
193
+ rubygems_version: 3.5.22
194
+ signing_key:
195
+ specification_version: 4
196
+ summary: Ruby bindings for PDF Oxide - high-performance PDF processing
197
+ test_files: []