pdfsink 0.1.2 → 0.2.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 +4 -4
- data/README.md +21 -1
- data/lib/pdfsink/cli.rb +19 -3
- data/lib/pdfsink/document.rb +26 -1
- data/lib/pdfsink/page.rb +22 -5
- data/lib/pdfsink/version.rb +2 -2
- data/lib/pdfsink.rb +1 -1
- metadata +2 -2
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: 6097674e65f4c20f1f715625ff7e45ba1de03af6c5a42e019fc52b4c7b471897
|
|
4
|
+
data.tar.gz: 6eaa5deed917aa12a71f1dce9918b814da3c2078eb2bcea530a82e8d62e21400
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: fbaf27f8a1e2fd4edb52c244b6e8a98f66eb35e71d1652bbaea5ff420f29fd32b7280defdb6290e40a9fec418882a8600ef152bcde7995055ebc071463f05c4e
|
|
7
|
+
data.tar.gz: 36566d61641837c8a85bfd23f468f184ab3bcd6e7e9e5e1a6ee5f0ebc30453b607423d8c4baf283b5057e024cc39c1753e101284c796f85ce367357c24f8652d
|
data/README.md
CHANGED
|
@@ -106,10 +106,30 @@ page.search(/total:\s*\$\d+/i)
|
|
|
106
106
|
# => [{"text" => "Total: $420", "x0" => ..., ...}]
|
|
107
107
|
```
|
|
108
108
|
|
|
109
|
+
### Read every page in one run
|
|
110
|
+
|
|
111
|
+
Each page method runs the pdfsink-rs binary for that page only. To read
|
|
112
|
+
every page, `load_all` runs it once for the whole document:
|
|
113
|
+
|
|
114
|
+
```ruby
|
|
115
|
+
doc = Pdfsink.open("report.pdf")
|
|
116
|
+
doc.load_all # one run; returns doc.pages
|
|
117
|
+
doc.pages.each do |page|
|
|
118
|
+
page.extract_text # no further runs
|
|
119
|
+
page.tables # no further runs (same strategy as load_all)
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
doc.load_all(strategy: :text) # load tables found with another strategy
|
|
123
|
+
```
|
|
124
|
+
|
|
125
|
+
Use the page methods when you need a few pages, and `load_all` when you
|
|
126
|
+
need all of them. `load_all` loads text and tables only; `extract_words`,
|
|
127
|
+
`objects`, `links` and `search` still run the binary for their page.
|
|
128
|
+
|
|
109
129
|
### Binary version
|
|
110
130
|
|
|
111
131
|
```ruby
|
|
112
|
-
Pdfsink.version # => "0.2.
|
|
132
|
+
Pdfsink.version # => "0.2.20+aim.1"
|
|
113
133
|
```
|
|
114
134
|
|
|
115
135
|
## Rails Integration
|
data/lib/pdfsink/cli.rb
CHANGED
|
@@ -30,7 +30,7 @@ module Pdfsink
|
|
|
30
30
|
# Override the resolved binary path (mainly for tests).
|
|
31
31
|
attr_writer :binary
|
|
32
32
|
|
|
33
|
-
# The pdfsink-rs version string, e.g. "
|
|
33
|
+
# The pdfsink-rs version string, e.g. "0.2.20+aim.1".
|
|
34
34
|
#
|
|
35
35
|
# The CLI has no version subcommand, so this reports the crate version
|
|
36
36
|
# the gem was built against.
|
|
@@ -51,11 +51,14 @@ module Pdfsink
|
|
|
51
51
|
|
|
52
52
|
# Extracted text for a single page.
|
|
53
53
|
#
|
|
54
|
+
# The binary always writes UTF-8. Open3 tags its output with the process
|
|
55
|
+
# locale, which is wrong under a C locale, so the tag is set here.
|
|
56
|
+
#
|
|
54
57
|
# @param path [String]
|
|
55
58
|
# @param page [Integer] 1-based page number
|
|
56
|
-
# @return [String]
|
|
59
|
+
# @return [String] UTF-8
|
|
57
60
|
def text(path, page)
|
|
58
|
-
run("text", path, page.to_s)
|
|
61
|
+
run("text", path, page.to_s).force_encoding(Encoding::UTF_8)
|
|
59
62
|
end
|
|
60
63
|
|
|
61
64
|
# Words with positions for a single page.
|
|
@@ -94,6 +97,19 @@ module Pdfsink
|
|
|
94
97
|
run_json("table", path, page.to_s, strategy)
|
|
95
98
|
end
|
|
96
99
|
|
|
100
|
+
# Document metadata plus the text and largest table of every page, in
|
|
101
|
+
# one run. Same payload as {info}, with "text" and "table" added to
|
|
102
|
+
# each entry in "pages". "text" has no trailing newline, unlike {text}.
|
|
103
|
+
#
|
|
104
|
+
# @param path [String]
|
|
105
|
+
# @param strategy [String] one of "lines", "lines_strict", "text", "explicit"
|
|
106
|
+
# @return [Hash]
|
|
107
|
+
# @raise [ParseError] if the binary prints nothing (too old to have +pages+)
|
|
108
|
+
def pages(path, strategy)
|
|
109
|
+
run_json("pages", path, strategy) or
|
|
110
|
+
raise ParseError, "pdfsink-rs pages printed nothing; the binary may be older than #{PDFSINK_RS_VERSION}"
|
|
111
|
+
end
|
|
112
|
+
|
|
97
113
|
private
|
|
98
114
|
|
|
99
115
|
def find_binary
|
data/lib/pdfsink/document.rb
CHANGED
|
@@ -5,7 +5,8 @@ module Pdfsink
|
|
|
5
5
|
#
|
|
6
6
|
# Opening is cheap: the path is validated and the document's +info+ payload
|
|
7
7
|
# (page count and per-page metadata) is fetched lazily on first access.
|
|
8
|
-
# {Page} objects are created on demand and memoized.
|
|
8
|
+
# {Page} objects are created on demand and memoized. {#load_all} reads
|
|
9
|
+
# every page's text and table in one run.
|
|
9
10
|
#
|
|
10
11
|
# @example
|
|
11
12
|
# doc = Pdfsink::Document.open("report.pdf")
|
|
@@ -77,6 +78,30 @@ module Pdfsink
|
|
|
77
78
|
pages.each(&block)
|
|
78
79
|
end
|
|
79
80
|
|
|
81
|
+
# Read the text and largest table of every page in one run of the
|
|
82
|
+
# binary. Afterwards {Page#extract_text}, and {Page#tables} with the same
|
|
83
|
+
# strategy, return without running it again. Use this when you need
|
|
84
|
+
# every page; for a few pages, the per-page methods are faster.
|
|
85
|
+
#
|
|
86
|
+
# Each call parses the whole document again, so a second strategy needs a
|
|
87
|
+
# second call. {Page#extract_words}, {Page#objects}, {Page#links} and
|
|
88
|
+
# {Page#search} are not preloaded.
|
|
89
|
+
#
|
|
90
|
+
# @param strategy [Symbol, String, nil] table-detection strategy
|
|
91
|
+
# @return [Array<Page>]
|
|
92
|
+
def load_all(strategy: nil)
|
|
93
|
+
strategy = TableStrategy.resolve(strategy)
|
|
94
|
+
payload = Cli.pages(path, strategy)
|
|
95
|
+
entries = payload["pages"]
|
|
96
|
+
|
|
97
|
+
@info = payload.merge("pages" => entries.map { |entry| entry.except("text", "table") })
|
|
98
|
+
entries.each.with_index(1) do |entry, number|
|
|
99
|
+
# The text command prints a trailing newline; pages does not.
|
|
100
|
+
page(number).preload(text: "#{entry['text']}\n", strategy: strategy, table: entry["table"])
|
|
101
|
+
end
|
|
102
|
+
pages
|
|
103
|
+
end
|
|
104
|
+
|
|
80
105
|
def inspect
|
|
81
106
|
"#<Pdfsink::Document path=#{path.inspect} pages=#{page_count}>"
|
|
82
107
|
end
|
data/lib/pdfsink/page.rb
CHANGED
|
@@ -3,10 +3,11 @@
|
|
|
3
3
|
module Pdfsink
|
|
4
4
|
# A single page of a {Document}.
|
|
5
5
|
#
|
|
6
|
-
# Each accessor
|
|
7
|
-
#
|
|
8
|
-
#
|
|
9
|
-
#
|
|
6
|
+
# Each accessor runs the pdfsink-rs binary for this page only; results are
|
|
7
|
+
# cached so repeated reads don't run it again. {Document#load_all} fills
|
|
8
|
+
# the text and tables of every page in one run. Page-level metadata
|
|
9
|
+
# (dimensions, rotation, bbox, object counts) comes from the document's
|
|
10
|
+
# +info+ payload and needs no extra run.
|
|
10
11
|
#
|
|
11
12
|
# @example
|
|
12
13
|
# doc = Pdfsink::Document.open("report.pdf")
|
|
@@ -25,6 +26,7 @@ module Pdfsink
|
|
|
25
26
|
@document = document
|
|
26
27
|
@number = number
|
|
27
28
|
@meta = meta
|
|
29
|
+
@tables = {}
|
|
28
30
|
end
|
|
29
31
|
|
|
30
32
|
# @return [Float] page width in PDF points
|
|
@@ -83,7 +85,22 @@ module Pdfsink
|
|
|
83
85
|
# @param strategy [Symbol, String, nil] table-detection strategy
|
|
84
86
|
# @return [Array<Array>, nil] rows of cells
|
|
85
87
|
def tables(strategy: nil)
|
|
86
|
-
|
|
88
|
+
strategy = TableStrategy.resolve(strategy)
|
|
89
|
+
return @tables[strategy] if @tables.key?(strategy)
|
|
90
|
+
|
|
91
|
+
@tables[strategy] = Cli.table(path, number, strategy)
|
|
92
|
+
end
|
|
93
|
+
|
|
94
|
+
# Store text and a table read by {Document#load_all}.
|
|
95
|
+
#
|
|
96
|
+
# @api private
|
|
97
|
+
# @param text [String]
|
|
98
|
+
# @param strategy [String] a resolved table strategy
|
|
99
|
+
# @param table [Array<Array>, nil]
|
|
100
|
+
# @return [void]
|
|
101
|
+
def preload(text:, strategy:, table:)
|
|
102
|
+
@extract_text = text
|
|
103
|
+
@tables[strategy] = table
|
|
87
104
|
end
|
|
88
105
|
|
|
89
106
|
def inspect
|
data/lib/pdfsink/version.rb
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
# frozen_string_literal: true
|
|
2
2
|
|
|
3
3
|
module Pdfsink
|
|
4
|
-
VERSION = "0.
|
|
4
|
+
VERSION = "0.2.0"
|
|
5
5
|
|
|
6
6
|
# Version of the pdfsink-rs crate this gem builds and wraps. Built from the
|
|
7
7
|
# matching git tag (v#{PDFSINK_RS_VERSION}), not crates.io -- the crate carries
|
|
8
8
|
# a [patch.crates-io] fix that cargo strips on publish.
|
|
9
|
-
PDFSINK_RS_VERSION = "0.2.
|
|
9
|
+
PDFSINK_RS_VERSION = "0.2.20+aim.1"
|
|
10
10
|
end
|
data/lib/pdfsink.rb
CHANGED
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: pdfsink
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.
|
|
4
|
+
version: 0.2.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Accountaim
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date: 2026-
|
|
11
|
+
date: 2026-10-24 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |
|
|
14
14
|
A Ruby gem that wraps the pdfsink-rs CLI, a fast pure-Rust PDF extraction
|