Compare commits

...
Author SHA1 Message Date
Abimael Martell 7210bebaad refactor(bindings): organize language packages 2026-07-17 16:55:09 -07:00
37 changed files with 691 additions and 1570 deletions
+63 -8
View File
@@ -42,9 +42,6 @@ jobs:
- name: Check formatting - name: Check formatting
run: cargo fmt --all -- --check run: cargo fmt --all -- --check
- name: Check WASM formatting
run: cargo fmt --manifest-path wasm/Cargo.toml -- --check
clippy: clippy:
name: Clippy name: Clippy
runs-on: ubuntu-latest runs-on: ubuntu-latest
@@ -99,21 +96,79 @@ jobs:
- name: Cache cargo - name: Cache cargo
uses: Swatinem/rust-cache@v2 uses: Swatinem/rust-cache@v2
with: with:
workspaces: |
wasm -> target
key: wasm key: wasm
- name: Check WebAssembly bindings - name: Check WebAssembly bindings
run: cargo check --manifest-path wasm/Cargo.toml --target wasm32-unknown-unknown run: cargo check --package pdf-inspector-wasm --target wasm32-unknown-unknown
- name: Check root package for WebAssembly - name: Check root package for WebAssembly
run: cargo check --target wasm32-unknown-unknown run: cargo check --target wasm32-unknown-unknown
- name: Lint WebAssembly bindings - name: Lint WebAssembly bindings
run: cargo clippy --manifest-path wasm/Cargo.toml --target wasm32-unknown-unknown -- -D warnings run: cargo clippy --package pdf-inspector-wasm --target wasm32-unknown-unknown -- -D warnings
- name: Install wasm-pack - name: Install wasm-pack
run: cargo install wasm-pack --version 0.15.0 --locked run: cargo install wasm-pack --version 0.15.0 --locked
- name: Test WebAssembly package - name: Test WebAssembly package
run: wasm-pack test --node --release wasm run: wasm-pack test --node --release bindings/wasm
node:
name: Node.js binding
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- uses: oven-sh/setup-bun@v2
with:
bun-version: latest
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
key: node
- name: Install dependencies
working-directory: bindings/node
run: bun install --frozen-lockfile
- name: Build binding
working-directory: bindings/node
run: bunx napi build --platform --release
- name: Run binding tests
working-directory: bindings/node
run: node test.mjs
python:
name: Python binding
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install Rust
uses: dtolnay/rust-toolchain@stable
- name: Cache cargo
uses: Swatinem/rust-cache@v2
with:
key: python
- name: Install build and test tools
run: python -m pip install maturin pytest
- name: Build wheel
run: maturin build --manifest-path bindings/python/Cargo.toml --release --out dist
- name: Install wheel
run: python -m pip install dist/*.whl
- name: Run binding tests
run: python -m pytest bindings/python/tests
+11 -8
View File
@@ -3,7 +3,7 @@ name: Publish Python package
on: on:
push: push:
branches: [main] branches: [main]
paths: ['pyproject.toml'] paths: ['bindings/python/pyproject.toml']
# Manual fallback: re-publish the current version without a version bump # Manual fallback: re-publish the current version without a version bump
# (e.g. first run after PyPI trusted publishing is configured). # (e.g. first run after PyPI trusted publishing is configured).
workflow_dispatch: workflow_dispatch:
@@ -31,7 +31,7 @@ jobs:
- name: Check if version changed - name: Check if version changed
id: check id: check
run: | run: |
NEW_VERSION=$(python3 -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("pyproject.toml").read_text())["project"]["version"])') NEW_VERSION=$(python3 -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("bindings/python/pyproject.toml").read_text())["project"]["version"])')
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT" echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
@@ -45,10 +45,13 @@ jobs:
exit 0 exit 0
fi fi
# .get(): the parent commit may predate the static version field if git cat-file -e HEAD~1:bindings/python/pyproject.toml 2>/dev/null; then
# (pyproject.toml used dynamic = ["version"]) — treat that as a change OLD_MANIFEST=bindings/python/pyproject.toml
# so the very first merge of this workflow publishes. else
OLD_VERSION=$(git show HEAD~1:pyproject.toml | python3 -c 'import sys, tomllib; print(tomllib.loads(sys.stdin.read())["project"].get("version", ""))') # Migration fallback for the commit that moved the Python package.
OLD_MANIFEST=pyproject.toml
fi
OLD_VERSION=$(git show "HEAD~1:$OLD_MANIFEST" | python3 -c 'import sys, tomllib; print(tomllib.loads(sys.stdin.read())["project"].get("version", ""))')
echo "old=$OLD_VERSION new=$NEW_VERSION" echo "old=$OLD_VERSION new=$NEW_VERSION"
if [ "$NEW_VERSION" = "$OLD_VERSION" ]; then if [ "$NEW_VERSION" = "$OLD_VERSION" ]; then
@@ -108,7 +111,7 @@ jobs:
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@v1
with: with:
target: ${{ matrix.target }} target: ${{ matrix.target }}
args: --release --out dist args: --manifest-path bindings/python/Cargo.toml --release --out dist
manylinux: auto manylinux: auto
- name: Upload wheel - name: Upload wheel
@@ -130,7 +133,7 @@ jobs:
uses: PyO3/maturin-action@v1 uses: PyO3/maturin-action@v1
with: with:
command: sdist command: sdist
args: --out dist args: --manifest-path bindings/python/Cargo.toml --out dist
- name: Upload sdist - name: Upload sdist
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
+15 -11
View File
@@ -3,7 +3,7 @@ name: Publish WebAssembly package
on: on:
push: push:
branches: [main] branches: [main]
paths: ['wasm/Cargo.toml'] paths: ['bindings/wasm/Cargo.toml']
workflow_dispatch: workflow_dispatch:
permissions: permissions:
@@ -31,21 +31,25 @@ jobs:
- name: Check package version - name: Check package version
id: check id: check
run: | run: |
NEW_VERSION=$(python3 -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("wasm/Cargo.toml").read_text())["package"]["version"])') NEW_VERSION=$(python3 -c 'import pathlib, tomllib; print(tomllib.loads(pathlib.Path("bindings/wasm/Cargo.toml").read_text())["package"]["version"])')
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT" echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT" echo "changed=true" >> "$GITHUB_OUTPUT"
elif git cat-file -e HEAD~1:wasm/Cargo.toml 2>/dev/null; then else
OLD_VERSION=$(git show HEAD~1:wasm/Cargo.toml | python3 -c 'import sys, tomllib; print(tomllib.loads(sys.stdin.read())["package"]["version"])') if git cat-file -e HEAD~1:bindings/wasm/Cargo.toml 2>/dev/null; then
OLD_MANIFEST=bindings/wasm/Cargo.toml
else
# Migration fallback for the commit that moved wasm/.
OLD_MANIFEST=wasm/Cargo.toml
fi
OLD_VERSION=$(git show "HEAD~1:$OLD_MANIFEST" | python3 -c 'import sys, tomllib; print(tomllib.loads(sys.stdin.read())["package"]["version"])')
if [ "$NEW_VERSION" = "$OLD_VERSION" ]; then if [ "$NEW_VERSION" = "$OLD_VERSION" ]; then
echo "changed=false" >> "$GITHUB_OUTPUT" echo "changed=false" >> "$GITHUB_OUTPUT"
echo "published=false" >> "$GITHUB_OUTPUT" echo "published=false" >> "$GITHUB_OUTPUT"
exit 0 exit 0
fi fi
echo "changed=true" >> "$GITHUB_OUTPUT" echo "changed=true" >> "$GITHUB_OUTPUT"
else
echo "changed=true" >> "$GITHUB_OUTPUT"
fi fi
if ! npm view "@firecrawl/pdf-inspector-wasm" name >/dev/null 2>&1; then if ! npm view "@firecrawl/pdf-inspector-wasm" name >/dev/null 2>&1; then
@@ -87,25 +91,25 @@ jobs:
run: cargo install wasm-pack --version 0.15.0 --locked run: cargo install wasm-pack --version 0.15.0 --locked
- name: Build browser package - name: Build browser package
run: wasm-pack build wasm --target web --scope firecrawl --out-dir pkg --release run: wasm-pack build bindings/wasm --target web --scope firecrawl --out-dir pkg --profile wasm-release --no-opt
- name: Prepare package metadata - name: Prepare package metadata
run: | run: |
node -e ' node -e '
const fs = require("fs") const fs = require("fs")
const path = "wasm/pkg/package.json" const path = "bindings/wasm/pkg/package.json"
const pkg = JSON.parse(fs.readFileSync(path, "utf8")) const pkg = JSON.parse(fs.readFileSync(path, "utf8"))
pkg.name = "@firecrawl/pdf-inspector-wasm" pkg.name = "@firecrawl/pdf-inspector-wasm"
pkg.description = "Browser WebAssembly bindings for the pdf-inspector Rust PDF parser" pkg.description = "Browser WebAssembly bindings for the pdf-inspector Rust PDF parser"
pkg.keywords = ["pdf", "pdf-parser", "webassembly", "wasm", "markdown", "rust", "firecrawl"] pkg.keywords = ["pdf", "pdf-parser", "webassembly", "wasm", "markdown", "rust", "firecrawl"]
pkg.repository = { type: "git", url: "https://github.com/firecrawl/pdf-inspector" } pkg.repository = { type: "git", url: "https://github.com/firecrawl/pdf-inspector" }
pkg.homepage = "https://github.com/firecrawl/pdf-inspector/tree/main/wasm" pkg.homepage = "https://github.com/firecrawl/pdf-inspector/tree/main/bindings/wasm"
pkg.publishConfig = { access: "public" } pkg.publishConfig = { access: "public" }
fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n") fs.writeFileSync(path, JSON.stringify(pkg, null, 2) + "\n")
' '
- name: Inspect package contents - name: Inspect package contents
run: npm pack --dry-run ./wasm/pkg run: npm pack --dry-run ./bindings/wasm/pkg
- name: Publish package - name: Publish package
run: npm publish ./wasm/pkg --provenance --access public run: npm publish ./bindings/wasm/pkg --provenance --access public
+19 -13
View File
@@ -3,7 +3,7 @@ name: Publish npm package
on: on:
push: push:
branches: [main] branches: [main]
paths: ['napi/package.json'] paths: ['bindings/node/package.json']
# Manual fallback: retry a publish that failed partway (per-package # Manual fallback: retry a publish that failed partway (per-package
# already-published checks make re-runs idempotent). # already-published checks make re-runs idempotent).
workflow_dispatch: workflow_dispatch:
@@ -31,7 +31,7 @@ jobs:
- name: Check if version changed - name: Check if version changed
id: check id: check
run: | run: |
NEW_VERSION=$(node -p "require('./napi/package.json').version") NEW_VERSION=$(node -p "require('./bindings/node/package.json').version")
echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT" echo "version=$NEW_VERSION" >> "$GITHUB_OUTPUT"
if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then if [ "${{ github.event_name }}" = "workflow_dispatch" ]; then
@@ -43,7 +43,13 @@ jobs:
exit 0 exit 0
fi fi
OLD_VERSION=$(git show HEAD~1:napi/package.json | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version") if git cat-file -e HEAD~1:bindings/node/package.json 2>/dev/null; then
OLD_MANIFEST=bindings/node/package.json
else
# Migration fallback for the commit that moved napi/.
OLD_MANIFEST=napi/package.json
fi
OLD_VERSION=$(git show "HEAD~1:$OLD_MANIFEST" | node -p "JSON.parse(require('fs').readFileSync('/dev/stdin','utf8')).version")
echo "old=$OLD_VERSION new=$NEW_VERSION" echo "old=$OLD_VERSION new=$NEW_VERSION"
if [ "$NEW_VERSION" != "$OLD_VERSION" ]; then if [ "$NEW_VERSION" != "$OLD_VERSION" ]; then
echo "changed=true" >> "$GITHUB_OUTPUT" echo "changed=true" >> "$GITHUB_OUTPUT"
@@ -82,24 +88,24 @@ jobs:
~/.cargo/registry/index/ ~/.cargo/registry/index/
~/.cargo/registry/cache/ ~/.cargo/registry/cache/
~/.cargo/git/db/ ~/.cargo/git/db/
napi/target/ target/
key: ${{ runner.os }}-cargo-napi-${{ hashFiles('**/Cargo.lock') }} key: ${{ runner.os }}-cargo-napi-${{ hashFiles('**/Cargo.lock') }}
restore-keys: | restore-keys: |
${{ runner.os }}-cargo-napi- ${{ runner.os }}-cargo-napi-
- name: Install dependencies - name: Install dependencies
working-directory: napi working-directory: bindings/node
run: bun install run: bun install --frozen-lockfile
- name: Build native addon - name: Build native addon
working-directory: napi working-directory: bindings/node
run: bunx napi build --platform --release run: bunx napi build --platform --release
- name: Upload native binary - name: Upload native binary
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
with: with:
name: bindings-${{ matrix.target }} name: bindings-${{ matrix.target }}
path: napi/*.node path: bindings/node/*.node
if-no-files-found: error if-no-files-found: error
- name: Upload generated JS bindings - name: Upload generated JS bindings
@@ -108,8 +114,8 @@ jobs:
with: with:
name: js-bindings name: js-bindings
path: | path: |
napi/index.js bindings/node/index.js
napi/index.d.ts bindings/node/index.d.ts
if-no-files-found: error if-no-files-found: error
publish: publish:
@@ -130,10 +136,10 @@ jobs:
- name: Download all artifacts - name: Download all artifacts
uses: actions/download-artifact@v4 uses: actions/download-artifact@v4
with: with:
path: napi/artifacts path: bindings/node/artifacts
- name: Publish platform packages - name: Publish platform packages
working-directory: napi working-directory: bindings/node
run: | run: |
VERSION="${{ needs.check-version.outputs.version }}" VERSION="${{ needs.check-version.outputs.version }}"
@@ -183,7 +189,7 @@ jobs:
done done
- name: Publish main package - name: Publish main package
working-directory: napi working-directory: bindings/node
run: | run: |
VERSION="${{ needs.check-version.outputs.version }}" VERSION="${{ needs.check-version.outputs.version }}"
+7 -8
View File
@@ -1,13 +1,12 @@
# Rust build artifacts # Rust build artifacts
/target/ /target/
/wasm/target/ /bindings/*/target/
/wasm/pkg/ /bindings/wasm/pkg/
debug/ debug/
*.pdb *.pdb
# Cargo lock (optional for libraries) # The workspace lock keeps binding builds reproducible.
Cargo.lock !/Cargo.lock
!/wasm/Cargo.lock
# IDE # IDE
.idea/ .idea/
@@ -27,9 +26,9 @@ Thumbs.db
# Build cache # Build cache
**/*.rs.bk **/*.rs.bk
# NAPI generated (regenerated by `napi prepublish` during CI) # Node generated files (regenerated by `napi prepublish` during CI)
napi/index.js bindings/node/index.js
napi/index.d.ts bindings/node/index.d.ts
# Local samples and scripts # Local samples and scripts
samples/ samples/
+4
View File
@@ -45,6 +45,10 @@ src/
classify.rs line classification (header, list, code, caption) classify.rs line classification (header, list, code, caption)
preprocess.rs drop cap merging, heading line merging preprocess.rs drop cap merging, heading line merging
postprocess.rs dot leaders, hyphenation, page numbers, URL formatting postprocess.rs dot leaders, hyphenation, page numbers, URL formatting
bindings/
node/ npm package, bundled CLI, and napi-rs adapter
python/ PyPI package, type stubs, tests, and PyO3 adapter
wasm/ browser npm package and wasm-bindgen adapter
``` ```
## Key design decisions ## Key design decisions
+4
View File
@@ -45,6 +45,10 @@ src/
classify.rs line classification (header, list, code, caption) classify.rs line classification (header, list, code, caption)
preprocess.rs drop cap merging, heading line merging preprocess.rs drop cap merging, heading line merging
postprocess.rs dot leaders, hyphenation, page numbers, URL formatting postprocess.rs dot leaders, hyphenation, page numbers, URL formatting
bindings/
node/ npm package, bundled CLI, and napi-rs adapter
python/ PyPI package, type stubs, tests, and PyO3 adapter
wasm/ browser npm package and wasm-bindgen adapter
``` ```
## Key design decisions ## Key design decisions
+436 -126
View File
@@ -94,16 +94,27 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c" checksum = "7f202df86484c868dbad7eaa557ef785d5c66295e41b460ef922eca0723b842c"
[[package]] [[package]]
name = "autocfg" name = "async-trait"
version = "1.5.0" version = "0.1.89"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c08606f8c3cbf4ce6ec8e28fb0014a2c086708fe954eaa885384a6165172e7e8" checksum = "9035ad2d096bed7955a320ee7e2230574d28fd3c3a0f186cbea1ff3c7eed5dbb"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "autocfg"
version = "1.5.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f2032f911046de80f0a198e0901378627c33f59ea0ac00e363d481118bd70a53"
[[package]] [[package]]
name = "bitflags" name = "bitflags"
version = "2.11.0" version = "2.13.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "843867be96c8daad0d758b57df9392b6d8d271134fce549de6ce169ff98a92af" checksum = "b4388bee8683e3d04af747c73422af53102d2bd24d9eadb6cbc100baef4b43f8"
[[package]] [[package]]
name = "block-buffer" name = "block-buffer"
@@ -125,9 +136,15 @@ dependencies = [
[[package]] [[package]]
name = "bumpalo" name = "bumpalo"
version = "3.20.2" version = "3.20.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5d20789868f4b01b2f2caec9f5c4e0213b41e3e5702a50157d699ae31ced2fcb" checksum = "72f5acc6cb2ba439de613abc23857ec3d78374d8ed5ac84e9d11336e87da8649"
[[package]]
name = "cast"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "37b2a672a2cb129a2e41c10b1224bb368f9f37a2b16b612598138befd7b37eb5"
[[package]] [[package]]
name = "cbc" name = "cbc"
@@ -140,9 +157,9 @@ dependencies = [
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.2.58" version = "1.2.64"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e1e928d4b69e3077709075a938a05ffbedfa53a84c8f766efbf8220bb1ff60e1" checksum = "dad887fd958be91b5098c0248def011f4523ab786cd411be668777e55063501f"
dependencies = [ dependencies = [
"find-msvc-tools", "find-msvc-tools",
"shlex", "shlex",
@@ -167,9 +184,9 @@ dependencies = [
[[package]] [[package]]
name = "chrono" name = "chrono"
version = "0.4.44" version = "0.4.45"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c673075a2e0e5f4a1dde27ce9dee1ea4558c7ffe648f576438a20ca1d2acc4b0" checksum = "1aa79e62e7697b8e29b513a68abacf485adcd1fe8284a4316c5ae868e6633327"
dependencies = [ dependencies = [
"iana-time-zone", "iana-time-zone",
"num-traits", "num-traits",
@@ -192,6 +209,16 @@ version = "1.0.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570" checksum = "1d07550c9036bf2ae0c684c4297d503f838287c83c53686d05370d0e139ae570"
[[package]]
name = "console_error_panic_hook"
version = "0.1.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a06aeb73f470f66dcdbf7223caeebb85984942f22f1adb2a088cf9668146bbbc"
dependencies = [
"cfg-if",
"wasm-bindgen",
]
[[package]] [[package]]
name = "convert_case" name = "convert_case"
version = "0.11.0" version = "0.11.0"
@@ -271,28 +298,15 @@ dependencies = [
[[package]] [[package]]
name = "ctor" name = "ctor"
version = "0.8.0" version = "1.0.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "352d39c2f7bef1d6ad73db6f5160efcaed66d94ef8c6c573a8410c00bf909a98" checksum = "a394189d59f9befacce833f337f7b1eca5e9a91221bcdd4d28e0114d96e597b3"
dependencies = [
"ctor-proc-macro",
"dtor",
]
[[package]]
name = "ctor-proc-macro"
version = "0.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "52560adf09603e58c9a7ee1fe1dcb95a16927b17c127f0ac02d6e768a0e25bc1"
[[package]] [[package]]
name = "deranged" name = "deranged"
version = "0.5.8" version = "0.5.8"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c" checksum = "7cd812cc2bc1d69d4764bd80df88b4317eaef9e773c75226407d9bc0876b211c"
dependencies = [
"powerfmt",
]
[[package]] [[package]]
name = "digest" name = "digest"
@@ -304,21 +318,6 @@ dependencies = [
"crypto-common", "crypto-common",
] ]
[[package]]
name = "dtor"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f1057d6c64987086ff8ed0fd3fbf377a6b7d205cc7715868cd401705f715cbe4"
dependencies = [
"dtor-proc-macro",
]
[[package]]
name = "dtor-proc-macro"
version = "0.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f678cf4a922c215c63e0de95eb1ff08a958a81d47e485cf9da1e27bf6305cfa5"
[[package]] [[package]]
name = "ecb" name = "ecb"
version = "0.1.2" version = "0.1.2"
@@ -330,9 +329,9 @@ dependencies = [
[[package]] [[package]]
name = "either" name = "either"
version = "1.15.0" version = "1.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48c757948c5ede0e46177b7add2e67155f70e33c07fea8284df6576da70b3719" checksum = "91622ff5e7162018101f2fea40d6ebf4a78bbe5a49736a2020649edf9693679e"
[[package]] [[package]]
name = "encoding_rs" name = "encoding_rs"
@@ -372,6 +371,22 @@ version = "1.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f" checksum = "877a4ace8713b0bcf2a4e7eec82529c029f1d0619886d18145fea96c3ffe5c0f"
[[package]]
name = "errno"
version = "0.3.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39cab71617ae0d63f51a36d69f866391735b51691dbda63cf6f96d042b63efeb"
dependencies = [
"libc",
"windows-sys",
]
[[package]]
name = "fastrand"
version = "2.4.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9f1f227452a390804cdb637b74a86990f2a7d7ba4b7d5693aac9b4dd6defd8d6"
[[package]] [[package]]
name = "find-msvc-tools" name = "find-msvc-tools"
version = "0.1.9" version = "0.1.9"
@@ -499,11 +514,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555" checksum = "0de51e6874e94e7bf76d726fc5d13ba782deca734ff60d5bb2fb2607c7406555"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"js-sys",
"libc", "libc",
"r-efi", "r-efi",
"rand_core", "rand_core",
"wasip2", "wasip2",
"wasip3", "wasip3",
"wasm-bindgen",
] ]
[[package]] [[package]]
@@ -517,9 +534,9 @@ dependencies = [
[[package]] [[package]]
name = "hashbrown" name = "hashbrown"
version = "0.16.1" version = "0.17.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100" checksum = "ed5909b6e89a2db4456e54cd5f673791d7eca6732202bbf2a9cc504fe2f9b84a"
[[package]] [[package]]
name = "heck" name = "heck"
@@ -558,17 +575,45 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954" checksum = "3d3067d79b975e8844ca9eb072e16b31c3c1c36928edf9c6789548c524d0d954"
[[package]] [[package]]
name = "indexmap" name = "include_dir"
version = "2.13.0" version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7714e70437a7dc3ac8eb7e6f8df75fd8eb422675fc7678aff7364301092b1017" checksum = "923d117408f1e49d914f1a379a309cffe4f18c05cf4e3d12e613a15fc81bd0dd"
dependencies = [
"include_dir_macros",
]
[[package]]
name = "include_dir_macros"
version = "0.7.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7cab85a7ed0bd5f0e76d93846e0147172bed2e2d3f859bcc33a8d9699cad1a75"
dependencies = [
"proc-macro2",
"quote",
]
[[package]]
name = "indexmap"
version = "2.14.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d466e9454f08e4a911e14806c24e16fba1b4c121d1ea474396f396069cf949d9"
dependencies = [ dependencies = [
"equivalent", "equivalent",
"hashbrown 0.16.1", "hashbrown 0.17.1",
"serde", "serde",
"serde_core", "serde_core",
] ]
[[package]]
name = "indoc"
version = "2.0.7"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "79cf5c93f93228cf8efb3ba362535fb11199ac548a09ce117c9b1adc3030d706"
dependencies = [
"rustversion",
]
[[package]] [[package]]
name = "inout" name = "inout"
version = "0.1.4" version = "0.1.4"
@@ -593,9 +638,9 @@ checksum = "8f42a60cbdf9a97f5d2305f08a87dc4e09308d1276d28c869c684d7777685682"
[[package]] [[package]]
name = "jiff" name = "jiff"
version = "0.2.23" version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1a3546dc96b6d42c5f24902af9e2538e82e39ad350b0c766eb3fbf2d8f3d8359" checksum = "4603d3033e49e2b0e31229fcab20a5d40089c607d975cd9c80551dc69eed9102"
dependencies = [ dependencies = [
"jiff-static", "jiff-static",
"jiff-tzdb-platform", "jiff-tzdb-platform",
@@ -603,14 +648,14 @@ dependencies = [
"portable-atomic", "portable-atomic",
"portable-atomic-util", "portable-atomic-util",
"serde_core", "serde_core",
"windows-sys", "windows-link",
] ]
[[package]] [[package]]
name = "jiff-static" name = "jiff-static"
version = "0.2.23" version = "0.2.28"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2a8c8b344124222efd714b73bb41f8b5120b27a7cc1c75593a6ff768d9d05aa4" checksum = "782d32378dddf207193ac91cefb848ad41abb58195c95168e1291227a0832b47"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@@ -634,11 +679,12 @@ dependencies = [
[[package]] [[package]]
name = "js-sys" name = "js-sys"
version = "0.3.94" version = "0.3.102"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e04e2ef80ce82e13552136fabeef8a5ed1f985a96805761cbb9a2c34e7664d9" checksum = "03d04c30968dffe80775bd4d7fb676131cd04a1fb46d2686dbffbaec2d9dfd31"
dependencies = [ dependencies = [
"once_cell", "cfg-if",
"futures-util",
"wasm-bindgen", "wasm-bindgen",
] ]
@@ -650,9 +696,9 @@ checksum = "09edd9e8b54e49e587e4f6295a7d29c3ea94d469cb40ab8ca70b288248a81db2"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.184" version = "0.2.186"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "48f5d2a454e16a5ea0f4ced81bd44e4cfc7bd3a507b61887c99fd3538b28e4af" checksum = "68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66"
[[package]] [[package]]
name = "libloading" name = "libloading"
@@ -665,10 +711,22 @@ dependencies = [
] ]
[[package]] [[package]]
name = "log" name = "libm"
version = "0.4.29" version = "0.2.16"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5e5032e24019045c762d3c0f28f5b6b8bbf38563a65908389bf7978758920897" checksum = "b6d2cec3eae94f9f509c767b45932f1ada8350c4bdb85af2fcab4a3c14807981"
[[package]]
name = "linux-raw-sys"
version = "0.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32a66949e030da00e8c7d4434b251670a91556f4144941d37452769c25d58a53"
[[package]]
name = "log"
version = "0.4.32"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "953f07c43838f8e6f9758cab68bf5bed85465e7587ebe0b823f1bcd81978ad3a"
[[package]] [[package]]
name = "lopdf" name = "lopdf"
@@ -713,9 +771,28 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.8.0" version = "2.8.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f8ca58f447f06ed17d5fc4043ce1b10dd205e060fb3ce5b979b8ed8e59ff3f79" checksum = "88904434abc2901f197fe8cc55f0445e7ded921dba5911dad2e2b39b48e663c4"
[[package]]
name = "memoffset"
version = "0.9.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "488016bfae457b036d996092f6cb448677611ce4449e970ceaf42695203f218a"
dependencies = [
"autocfg",
]
[[package]]
name = "minicov"
version = "0.3.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4869b6a491569605d66d3952bcdf03df789e5b536e5f0cf7758a7f08a55ae24d"
dependencies = [
"cc",
"walkdir",
]
[[package]] [[package]]
name = "miniz_oxide" name = "miniz_oxide"
@@ -729,9 +806,9 @@ dependencies = [
[[package]] [[package]]
name = "napi" name = "napi"
version = "3.8.4" version = "3.10.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fb7848c221fb7bb789e02f01875287ebb1e078b92a6566a34de01ef8806e7c2b" checksum = "6826e5ddc15589b2d68c8ad5321c18e85d40488e93e32962f362e572669bccf6"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"ctor", "ctor",
@@ -746,15 +823,15 @@ dependencies = [
[[package]] [[package]]
name = "napi-build" name = "napi-build"
version = "2.3.1" version = "2.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d376940fd5b723c6893cd1ee3f33abbfd86acb1cd1ec079f3ab04a2a3bc4d3b1" checksum = "c9c366d2c8c60b86fa632df75f745509b52f9128f91a6bad4c796e44abb505e1"
[[package]] [[package]]
name = "napi-derive" name = "napi-derive"
version = "3.5.3" version = "3.5.10"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "60867ff9a6f76e82350e0c3420cb0736f5866091b61d7d8a024baa54b0ec17dd" checksum = "b0fe526e81c105d3640516fcde83909dd1afe757c0d7a15af58830b5bc0fb9a1"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"ctor", "ctor",
@@ -766,9 +843,9 @@ dependencies = [
[[package]] [[package]]
name = "napi-derive-backend" name = "napi-derive-backend"
version = "5.0.2" version = "5.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "f0864cf6a82e2cfb69067374b64c9253d7e910e5b34db833ed7495dda56ccb18" checksum = "514281397bcddd9ea9a876c7a21a57bff2374237a000ca9a64ea0211ec1993e2"
dependencies = [ dependencies = [
"convert_case", "convert_case",
"proc-macro2", "proc-macro2",
@@ -779,9 +856,9 @@ dependencies = [
[[package]] [[package]]
name = "napi-sys" name = "napi-sys"
version = "3.2.1" version = "3.2.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8eb602b84d7c1edae45e50bbf1374696548f36ae179dfa667f577e384bb90c2b" checksum = "73e43cf2eb0bd1bf95a43c07c076ebd2da5d1e015a71c3d201faeffffcc0ecac"
dependencies = [ dependencies = [
"libloading", "libloading",
] ]
@@ -802,10 +879,19 @@ dependencies = [
] ]
[[package]] [[package]]
name = "num-conv" name = "nu-ansi-term"
version = "0.2.1" version = "0.50.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c6673768db2d862beb9b39a78fdcb1a69439615d5794a1be50caa9bc92c81967" checksum = "7957b9740744892f114936ab4a57b3f487491bbeafaf8083688b16841a4240e5"
dependencies = [
"windows-sys",
]
[[package]]
name = "num-conv"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "521739c6d2bac4aa25192232afe6841231376b2b26d4d9fae5ecf8ca5772e441"
[[package]] [[package]]
name = "num-traits" name = "num-traits"
@@ -814,6 +900,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841" checksum = "071dfc062690e90b734c0b2273ce72ad0ffa95f0c74596bc250dcfd960262841"
dependencies = [ dependencies = [
"autocfg", "autocfg",
"libm",
] ]
[[package]] [[package]]
@@ -828,23 +915,31 @@ version = "1.70.2"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe" checksum = "384b8ab6d37215f3c5301a95a4accb5d64aa607f1fcb26a11b5303878451b4fe"
[[package]]
name = "oorandom"
version = "11.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d6790f58c7ff633d8771f42965289203411a5e5c68388703c06e14f24770b41e"
[[package]] [[package]]
name = "pdf-inspector" name = "pdf-inspector"
version = "0.1.6" version = "0.1.6"
dependencies = [ dependencies = [
"env_logger", "env_logger",
"include_dir",
"log", "log",
"lopdf", "lopdf",
"once_cell", "once_cell",
"rayon", "rayon",
"regex", "regex",
"tempfile",
"thiserror", "thiserror",
"ttf-parser", "ttf-parser",
"unicode-normalization", "unicode-normalization",
] ]
[[package]] [[package]]
name = "pdf-inspector-napi" name = "pdf-inspector-node"
version = "0.2.2" version = "0.2.2"
dependencies = [ dependencies = [
"napi", "napi",
@@ -853,6 +948,27 @@ dependencies = [
"pdf-inspector", "pdf-inspector",
] ]
[[package]]
name = "pdf-inspector-python"
version = "0.2.5"
dependencies = [
"pdf-inspector",
"pyo3",
]
[[package]]
name = "pdf-inspector-wasm"
version = "0.1.2"
dependencies = [
"console_error_panic_hook",
"js-sys",
"pdf-inspector",
"serde",
"serde-wasm-bindgen",
"wasm-bindgen",
"wasm-bindgen-test",
]
[[package]] [[package]]
name = "pin-project-lite" name = "pin-project-lite"
version = "0.2.17" version = "0.2.17"
@@ -867,9 +983,9 @@ checksum = "c33a9471896f1c69cecef8d20cbe2f7accd12527ce60845ff44c153bb2a21b49"
[[package]] [[package]]
name = "portable-atomic-util" name = "portable-atomic-util"
version = "0.2.6" version = "0.2.7"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "091397be61a01d4be58e7841595bd4bfedb15f1cd54977d79b8271e94ed799a3" checksum = "c2a106d1259c23fac8e543272398ae0e3c0b8d33c88ed73d0cc71b0f1d902618"
dependencies = [ dependencies = [
"portable-atomic", "portable-atomic",
] ]
@@ -899,6 +1015,68 @@ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "pyo3"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8970a78afe0628a3e3430376fc5fd76b6b45c4d43360ffd6cdd40bdde72b682a"
dependencies = [
"indoc",
"libc",
"memoffset",
"once_cell",
"portable-atomic",
"pyo3-build-config",
"pyo3-ffi",
"pyo3-macros",
"unindent",
]
[[package]]
name = "pyo3-build-config"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "458eb0c55e7ece017adeba38f2248ff3ac615e53660d7c71a238d7d2a01c7598"
dependencies = [
"once_cell",
"target-lexicon",
]
[[package]]
name = "pyo3-ffi"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7114fe5457c61b276ab77c5055f206295b812608083644a5c5b2640c3102565c"
dependencies = [
"libc",
"pyo3-build-config",
]
[[package]]
name = "pyo3-macros"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a8725c0a622b374d6cb051d11a0983786448f7785336139c3c94f5aa6bef7e50"
dependencies = [
"proc-macro2",
"pyo3-macros-backend",
"quote",
"syn",
]
[[package]]
name = "pyo3-macros-backend"
version = "0.25.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4109984c22491085343c05b0dbc54ddc405c3cf7b4374fc533f5c3313a572ccc"
dependencies = [
"heck",
"proc-macro2",
"pyo3-build-config",
"quote",
"syn",
]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.45" version = "1.0.45"
@@ -916,9 +1094,9 @@ checksum = "f8dcc9c7d52a811697d2151c701e0d08956f92b0e24136cf4cf27b57a6a0d9bf"
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bc266eb313df6c5c09c1c7b1fbe2510961e5bcd3add930c1e31f7ed9da0feff8" checksum = "d2e8e8bcc7961af1fdac401278c6a831614941f6164ee3bf4ce61b7edb162207"
dependencies = [ dependencies = [
"chacha20", "chacha20",
"getrandom", "getrandom",
@@ -927,9 +1105,9 @@ dependencies = [
[[package]] [[package]]
name = "rand_core" name = "rand_core"
version = "0.10.0" version = "0.10.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0c8d0fd677905edcbeedbf2edb6494d676f0e98d54d5cf9bda0b061cb8fb8aba" checksum = "63b8176103e19a2643978565ca18b50549f6101881c443590420e4dc998a3c69"
[[package]] [[package]]
name = "rangemap" name = "rangemap"
@@ -939,9 +1117,9 @@ checksum = "973443cf09a9c8656b574a866ab68dfa19f0867d0340648c7d2f6a71b8a8ea68"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.11.0" version = "1.12.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "368f01d005bf8fd9b1206fb6fa653e6c4a81ceb1466406b81792d87c5677a58f" checksum = "fb39b166781f92d482534ef4b4b1b2568f42613b53e5b6c160e24cfbfa30926d"
dependencies = [ dependencies = [
"either", "either",
"rayon-core", "rayon-core",
@@ -959,9 +1137,9 @@ dependencies = [
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.12.3" version = "1.12.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e10754a14b9137dd7b1e3e5b0493cc9171fdd105e0ab477f51b72e7f3ac0e276" checksum = "f1292b7759ae1cb9ec195452d1390a074f0cd8541ab7a5a8c31cd6db45d4a6ba"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@@ -982,15 +1160,28 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.8.10" version = "0.8.11"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc897dd8d9e8bd1ed8cdad82b5966c3e0ecae09fb1907d58efaa013543185d0a" checksum = "d6f6ff9a378485b298a5286656da665ba74413d36db0979633275d2e708145d4"
[[package]] [[package]]
name = "rustc-hash" name = "rustc-hash"
version = "2.1.2" version = "2.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "94300abf3f1ae2e2b8ffb7b58043de3d399c73fa6f4b73826402a5c457614dbe" checksum = "6b1e7f9a428571be2dc5bc0505c13fb6bf936822b894ec87abf8a08a4e51742d"
[[package]]
name = "rustix"
version = "1.1.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b6fe4565b9518b83ef4f91bb47ce29620ca828bd32cb7e408f0062e9930ba190"
dependencies = [
"bitflags",
"errno",
"libc",
"linux-raw-sys",
"windows-sys",
]
[[package]] [[package]]
name = "rustversion" name = "rustversion"
@@ -999,10 +1190,19 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d" checksum = "b39cdef0fa800fc44525c84ccb54a029961a8215f9619753635a9c0d2538d46d"
[[package]] [[package]]
name = "semver" name = "same-file"
version = "1.0.27" version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d767eb0aabc880b29956c35734170f26ed551a859dbd361d140cdbeca61ab1e2" checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502"
dependencies = [
"winapi-util",
]
[[package]]
name = "semver"
version = "1.0.28"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8a7852d02fc848982e0c167ef163aaff9cd91dc640ba85e263cb1ce46fae51cd"
[[package]] [[package]]
name = "serde" name = "serde"
@@ -1011,6 +1211,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e" checksum = "9a8e94ea7f378bd32cbbd37198a4a91436180c5bb472411e48b5ec2e2124ae9e"
dependencies = [ dependencies = [
"serde_core", "serde_core",
"serde_derive",
]
[[package]]
name = "serde-wasm-bindgen"
version = "0.6.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8302e169f0eddcc139c70f139d19d6467353af16f9fce27e8c30158036a1e16b"
dependencies = [
"js-sys",
"serde",
"wasm-bindgen",
] ]
[[package]] [[package]]
@@ -1035,9 +1247,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_json" name = "serde_json"
version = "1.0.149" version = "1.0.150"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86" checksum = "e8014e44b4736ed0538adeecded0fce2a272f22dc9578a7eb6b2d9993c74cfb9"
dependencies = [ dependencies = [
"itoa", "itoa",
"memchr", "memchr",
@@ -1059,9 +1271,9 @@ dependencies = [
[[package]] [[package]]
name = "shlex" name = "shlex"
version = "1.3.0" version = "2.0.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" checksum = "f8fadd59c855ef2080decdef8ff161eb6661b86933c9d82e5ba29dc602a55aba"
[[package]] [[package]]
name = "simd-adler32" name = "simd-adler32"
@@ -1088,15 +1300,34 @@ dependencies = [
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.117" version = "2.0.118"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e665b8803e7b1d2a727f4023456bbbbe74da67099c585258af0ad9c5013b9b99" checksum = "1b9ae57f904213ebb649ce6895b8a66c66f0203b9319718f69a5612a065b1422"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "target-lexicon"
version = "0.13.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "adb6935a6f5c20170eeceb1a3835a49e12e19d792f6dd344ccc76a985ca5a6ca"
[[package]]
name = "tempfile"
version = "3.27.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "32497e9a4c7b38532efcdebeef879707aa9f794296a4f0244f6f69e9bc8574bd"
dependencies = [
"fastrand",
"getrandom",
"once_cell",
"rustix",
"windows-sys",
]
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "2.0.18" version = "2.0.18"
@@ -1119,12 +1350,11 @@ dependencies = [
[[package]] [[package]]
name = "time" name = "time"
version = "0.3.47" version = "0.3.49"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "743bd48c283afc0388f9b8827b976905fb217ad9e647fae3a379a9283c4def2c" checksum = "711a53c2d47bbd818258c498c8dbfe186a2526c631495cfe7e078567f86b8469"
dependencies = [ dependencies = [
"deranged", "deranged",
"itoa",
"num-conv", "num-conv",
"powerfmt", "powerfmt",
"serde_core", "serde_core",
@@ -1134,15 +1364,15 @@ dependencies = [
[[package]] [[package]]
name = "time-core" name = "time-core"
version = "0.1.8" version = "0.1.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7694e1cfe791f8d31026952abf09c69ca6f6fa4e1a1229e18988f06a04a12dca" checksum = "9e1c906769ad99c88eaa54e728060edef082f8e358ff32030cb7c7d315e81109"
[[package]] [[package]]
name = "time-macros" name = "time-macros"
version = "0.2.27" version = "0.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2e70e4c5a0e0a8a4823ad65dfe1a6930e4f4d756dcd9dd7939022b5e8c501215" checksum = "71c652a3727a9cbb9a02f707f530b618ce00d0ccd762009c8c23bd191df3c17d"
dependencies = [ dependencies = [
"num-conv", "num-conv",
"time-core", "time-core",
@@ -1171,9 +1401,9 @@ checksum = "d2df906b07856748fa3f6e0ad0cbaa047052d4a7dd609e231c4f72cee8c36f31"
[[package]] [[package]]
name = "typenum" name = "typenum"
version = "1.19.0" version = "1.20.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "562d481066bde0658276a35467c4af00bdc6ee726305698a55b86e61d7ad82bb" checksum = "b6f5e870be6c3b371b77fe0ee0bafb859fa4964b4404c27de1d380043c4dda20"
[[package]] [[package]]
name = "unicode-bidi" name = "unicode-bidi"
@@ -1204,9 +1434,9 @@ checksum = "7df058c713841ad818f1dc5d3fd88063241cc61f49f5fbea4b951e8cf5a8d71d"
[[package]] [[package]]
name = "unicode-segmentation" name = "unicode-segmentation"
version = "1.13.2" version = "1.13.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9629274872b2bfaf8d66f5f15725007f635594914870f65218920345aa11aa8c" checksum = "c6f5d3c3b1bf09027a88a6bc961fc00497d651009560b5463668dc81b0fa87a8"
[[package]] [[package]]
name = "unicode-xid" name = "unicode-xid"
@@ -1214,6 +1444,12 @@ version = "0.2.6"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853" checksum = "ebc1c04c71510c7f702b52b7c350734c9ff1295c464a03335b00bb84fc54f853"
[[package]]
name = "unindent"
version = "0.2.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7264e107f553ccae879d21fbea1d6724ac785e8c3bfc762137959b5802826ef3"
[[package]] [[package]]
name = "utf8parse" name = "utf8parse"
version = "0.2.2" version = "0.2.2"
@@ -1227,12 +1463,22 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a"
[[package]] [[package]]
name = "wasip2" name = "walkdir"
version = "1.0.2+wasi-0.2.9" version = "2.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9517f9239f02c069db75e65f174b3da828fe5f5b945c4dd26bd25d89c03ebcf5" checksum = "29790946404f91d9c5d06f9874efddea1dc06c5efe94541a7d6863108e3a5e4b"
dependencies = [ dependencies = [
"wit-bindgen", "same-file",
"winapi-util",
]
[[package]]
name = "wasip2"
version = "1.0.4+wasi-0.2.12"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b67efb37e106e55ce722a510d6b5f9c17f083e5fc79afc2badeb12cc313d9487"
dependencies = [
"wit-bindgen 0.57.1",
] ]
[[package]] [[package]]
@@ -1241,14 +1487,14 @@ version = "0.4.0+wasi-0.3.0-rc-2026-01-06"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5" checksum = "5428f8bf88ea5ddc08faddef2ac4a67e390b88186c703ce6dbd955e1c145aca5"
dependencies = [ dependencies = [
"wit-bindgen", "wit-bindgen 0.51.0",
] ]
[[package]] [[package]]
name = "wasm-bindgen" name = "wasm-bindgen"
version = "0.2.117" version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0551fc1bb415591e3372d0bc4780db7e587d84e2a7e79da121051c5c4b89d0b0" checksum = "8ddb3f79143bced6de84270411622a2699cee572fc0875aeaf1e7867cf9fca1a"
dependencies = [ dependencies = [
"cfg-if", "cfg-if",
"once_cell", "once_cell",
@@ -1258,10 +1504,20 @@ dependencies = [
] ]
[[package]] [[package]]
name = "wasm-bindgen-macro" name = "wasm-bindgen-futures"
version = "0.2.117" version = "0.4.75"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fbdf9a35adf44786aecd5ff89b4563a90325f9da0923236f6104e603c7e86be" checksum = "503b14d284f2c8dac03b819967e155ea753f573586193b2b2c95990cb5d69280"
dependencies = [
"js-sys",
"wasm-bindgen",
]
[[package]]
name = "wasm-bindgen-macro"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4e21a184b13fb19e157296e2c46056aec9092264fab83e4ba59e68c61b323c3d"
dependencies = [ dependencies = [
"quote", "quote",
"wasm-bindgen-macro-support", "wasm-bindgen-macro-support",
@@ -1269,9 +1525,9 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-macro-support" name = "wasm-bindgen-macro-support"
version = "0.2.117" version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dca9693ef2bab6d4e6707234500350d8dad079eb508dca05530c85dc3a529ff2" checksum = "fecefd9c35bd935a20fc3fc344b5f29138961e4f47fb03297d88f2587afb5ebd"
dependencies = [ dependencies = [
"bumpalo", "bumpalo",
"proc-macro2", "proc-macro2",
@@ -1282,13 +1538,52 @@ dependencies = [
[[package]] [[package]]
name = "wasm-bindgen-shared" name = "wasm-bindgen-shared"
version = "0.2.117" version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "39129a682a6d2d841b6c429d0c51e5cb0ed1a03829d8b3d1e69a011e62cb3d3b" checksum = "23939e44bb9a5d7576fa2b563dc2e136628f1224e88a8deed09e04858b77871f"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]]
name = "wasm-bindgen-test"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d16931d57bcdd6a0dcc11254bdd1388827690c1b6807f0d2836f59a4f9eb30ac"
dependencies = [
"async-trait",
"cast",
"js-sys",
"libm",
"minicov",
"nu-ansi-term",
"num-traits",
"oorandom",
"serde",
"serde_json",
"wasm-bindgen",
"wasm-bindgen-futures",
"wasm-bindgen-test-macro",
"wasm-bindgen-test-shared",
]
[[package]]
name = "wasm-bindgen-test-macro"
version = "0.3.75"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "fccaddcb2cd722baa7453b4c3d2cb2a3071597bb91f7a4373e8775bdb151778c"
dependencies = [
"proc-macro2",
"quote",
"syn",
]
[[package]]
name = "wasm-bindgen-test-shared"
version = "0.2.125"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3746ad029217960123cf2ebf939dda51eb931ba9f8f09c117e39c820b96aa794"
[[package]] [[package]]
name = "wasm-encoder" name = "wasm-encoder"
version = "0.244.0" version = "0.244.0"
@@ -1329,6 +1624,15 @@ version = "0.1.12"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88" checksum = "a28ac98ddc8b9274cb41bb4d9d4d5c425b6020c50c46f25559911905610b4a88"
[[package]]
name = "winapi-util"
version = "0.1.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c2a7b1c03c876122aa43f3020e6c3c3ee5c05081c9a00739faf7503aeba10d22"
dependencies = [
"windows-sys",
]
[[package]] [[package]]
name = "windows-core" name = "windows-core"
version = "0.62.2" version = "0.62.2"
@@ -1406,6 +1710,12 @@ dependencies = [
"wit-bindgen-rust-macro", "wit-bindgen-rust-macro",
] ]
[[package]]
name = "wit-bindgen"
version = "0.57.1"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "1ebf944e87a7c253233ad6766e082e3cd714b5d03812acc24c318f549614536e"
[[package]] [[package]]
name = "wit-bindgen-core" name = "wit-bindgen-core"
version = "0.51.0" version = "0.51.0"
+17 -11
View File
@@ -16,19 +16,12 @@ include = [
"/external/bcmaps/**", "/external/bcmaps/**",
"/docs/rust-api.md", "/docs/rust-api.md",
"/LICENSE", "/LICENSE",
# maturin derives the sdist file list from this allowlist; the stub must
# ship so wheels built from the sdist keep their type hints.
"/pdf_inspector.pyi",
] ]
[lib] [lib]
name = "pdf_inspector" name = "pdf_inspector"
crate-type = ["lib", "cdylib"]
[dependencies] [dependencies]
# Python bindings
pyo3 = { version = "0.25", features = ["extension-module", "abi3-py38"], optional = true }
# Error handling # Error handling
thiserror = "2.0" thiserror = "2.0"
@@ -59,10 +52,6 @@ include_dir = "0.7"
[dev-dependencies] [dev-dependencies]
tempfile = "3.3" tempfile = "3.3"
[features]
default = []
python = ["pyo3"]
[[bin]] [[bin]]
name = "pdf2md" name = "pdf2md"
path = "src/bin/pdf2md.rs" path = "src/bin/pdf2md.rs"
@@ -74,3 +63,20 @@ path = "src/bin/detect_pdf.rs"
[[bin]] [[bin]]
name = "dump_ops" name = "dump_ops"
path = "src/bin/dump_ops.rs" path = "src/bin/dump_ops.rs"
[workspace]
members = ["bindings/node", "bindings/python", "bindings/wasm"]
default-members = ["."]
resolver = "2"
# Native packages benefit from LTO. Browser builds use a size-focused custom
# profile selected by the wasm-pack release command.
[profile.release]
lto = true
strip = "debuginfo"
[profile.wasm-release]
inherits = "release"
codegen-units = 1
opt-level = "s"
strip = true
+10 -9
View File
@@ -5,7 +5,7 @@
[![PyPI](https://img.shields.io/pypi/v/pdf-inspector.svg)](https://pypi.org/project/pdf-inspector/) [![PyPI](https://img.shields.io/pypi/v/pdf-inspector.svg)](https://pypi.org/project/pdf-inspector/)
[![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE) [![License: MIT](https://img.shields.io/badge/license-MIT-blue.svg)](LICENSE)
Fast Rust library for PDF classification and text extraction. Detects whether a PDF is text-based or scanned, extracts text with position awareness, and converts to clean Markdown — all without OCR. Includes bindings for [Python](docs/python.md), [Node.js](napi/README.md), and [browser WebAssembly](wasm/README.md). Fast Rust library for PDF classification and text extraction. Detects whether a PDF is text-based or scanned, extracts text with position awareness, and converts to clean Markdown — all without OCR. Includes bindings for [Python](bindings/python/README.md), [Node.js](bindings/node/README.md), and [browser WebAssembly](bindings/wasm/README.md).
Built by [Firecrawl](https://firecrawl.dev) to handle text-based PDFs locally in under 200ms, skipping expensive OCR services for the ~54% of PDFs that don't need them. Built by [Firecrawl](https://firecrawl.dev) to handle text-based PDFs locally in under 200ms, skipping expensive OCR services for the ~54% of PDFs that don't need them.
@@ -47,8 +47,7 @@ Use the [paired benchmark harness](docs/benchmarking.md) to compare two local bu
### Python ### Python
```bash ```bash
pip install maturin pip install pdf-inspector
maturin develop --release
``` ```
```python ```python
@@ -59,7 +58,7 @@ print(result.pdf_type) # "text_based", "scanned", "image_based", "mixed"
print(result.markdown) # Markdown string or None print(result.markdown) # Markdown string or None
``` ```
> Full API reference: [docs/python.md](docs/python.md) > Full API reference: [bindings/python/README.md](bindings/python/README.md)
### Node.js ### Node.js
@@ -76,7 +75,7 @@ console.log(result.pdfType); // "TextBased", "Scanned", "ImageBased", "Mixed"
console.log(result.markdown); // Markdown string or null console.log(result.markdown); // Markdown string or null
``` ```
> Full API reference: [napi/README.md](napi/README.md) > Full API reference: [bindings/node/README.md](bindings/node/README.md)
### Browser WebAssembly ### Browser WebAssembly
@@ -96,7 +95,7 @@ console.log(result.pdfType);
console.log(result.markdown); console.log(result.markdown);
``` ```
> Full API reference: [wasm/README.md](wasm/README.md) > Full API reference: [bindings/wasm/README.md](bindings/wasm/README.md)
### Rust ### Rust
@@ -197,7 +196,6 @@ The document is loaded **once** via `load_document_from_path` / `load_document_f
``` ```
src/ src/
lib.rs — Public API, PdfOptions builder, convenience functions lib.rs — Public API, PdfOptions builder, convenience functions
python.rs — PyO3 Python bindings
types.rs — Shared types: TextItem, TextLine, PdfRect, ItemType types.rs — Shared types: TextItem, TextLine, PdfRect, ItemType
text_utils.rs — Character/text helpers (CJK, RTL, ligatures, bold/italic) text_utils.rs — Character/text helpers (CJK, RTL, ligatures, bold/italic)
process_mode.rs — ProcessMode enum (DetectOnly, Analyze, Full) process_mode.rs — ProcessMode enum (DetectOnly, Analyze, Full)
@@ -208,8 +206,11 @@ src/
tables/ — Table detection and formatting tables/ — Table detection and formatting
markdown/ — Markdown conversion and structure detection markdown/ — Markdown conversion and structure detection
bin/ — CLI tools (pdf2md, detect_pdf) bin/ — CLI tools (pdf2md, detect_pdf)
napi/ — Node.js/Bun bindings (napi-rs) bindings/
wasm/ Browser bindings (wasm-bindgen) node/Node.js/Bun package and CLI (napi-rs)
python/ — Python package (PyO3 + maturin)
wasm/ — Browser package (wasm-bindgen)
tests/fixtures/ — Shared PDFs used across core and binding tests
``` ```
## How classification works ## How classification works
+13
View File
@@ -0,0 +1,13 @@
# Language bindings
The Rust crate at the repository root owns PDF parsing, extraction, and Markdown conversion. Each directory here is a thin package adapter that translates the core API into the conventions of its runtime.
| Binding | Public package | Implementation |
|---|---|---|
| [Node.js](node/README.md) | `@firecrawl/pdf-inspector` | napi-rs |
| [Python](python/README.md) | `pdf-inspector` | PyO3 + maturin |
| [Browser WebAssembly](wasm/README.md) | `@firecrawl/pdf-inspector-wasm` | wasm-bindgen |
The public package names and APIs are independent from these repository paths. Binding-specific metadata, tests, examples, and release inputs live with their adapter; shared PDF fixtures remain in [`tests/fixtures`](../tests/fixtures).
Versions remain independent for now. A later release-policy change can align them without mixing that change into the structural reorganization.
+3
View File
@@ -0,0 +1,3 @@
target/
node_modules/
*.node
+3 -6
View File
@@ -1,19 +1,16 @@
[package] [package]
name = "pdf-inspector-napi" name = "pdf-inspector-node"
version = "0.2.2" version = "0.2.2"
edition = "2021" edition = "2021"
publish = false
[lib] [lib]
crate-type = ["cdylib"] crate-type = ["cdylib"]
[dependencies] [dependencies]
pdf-inspector = { path = ".." } pdf-inspector = { path = "../.." }
napi = { version = "3.0.0", features = ["serde-json"] } napi = { version = "3.0.0", features = ["serde-json"] }
napi-derive = "3.0.0" napi-derive = "3.0.0"
[build-dependencies] [build-dependencies]
napi-build = "2" napi-build = "2"
[profile.release]
lto = true
strip = "debuginfo"
+9 -3
View File
@@ -8,9 +8,9 @@
"@napi-rs/cli": "^3.4.1", "@napi-rs/cli": "^3.4.1",
}, },
"optionalDependencies": { "optionalDependencies": {
"@firecrawl/pdf-inspector-darwin-arm64": "1.11.0", "@firecrawl/pdf-inspector-darwin-arm64": "1.11.1",
"@firecrawl/pdf-inspector-linux-x64-gnu": "1.11.0", "@firecrawl/pdf-inspector-linux-x64-gnu": "1.11.1",
"@firecrawl/pdf-inspector-win32-x64-msvc": "1.11.0", "@firecrawl/pdf-inspector-win32-x64-msvc": "1.11.1",
}, },
}, },
}, },
@@ -21,6 +21,12 @@
"@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="], "@emnapi/wasi-threads": ["@emnapi/wasi-threads@1.2.1", "", { "dependencies": { "tslib": "^2.4.0" } }, "sha512-uTII7OYF+/Mes/MrcIOYp5yOtSMLBWSIoLPpcgwipoiKbli6k322tcoFsxoIIxPDqW01SQGAgko4EzZi2BNv2w=="],
"@firecrawl/pdf-inspector-darwin-arm64": ["@firecrawl/pdf-inspector-darwin-arm64@1.11.1", "", { "os": "darwin", "cpu": "arm64" }, "sha512-MYworvuQ84dRxMhVmhSuSP8gVdrxqKfnTC+spGc+OIEaJGHNuzgBUzgi9O7p3wSP/hkK9QdCDEbl6wdBO9a4rA=="],
"@firecrawl/pdf-inspector-linux-x64-gnu": ["@firecrawl/pdf-inspector-linux-x64-gnu@1.11.1", "", { "os": "linux", "cpu": "x64" }, "sha512-Vyp7EpmplnWFsyi7YGK1yKE97PIrueIpo7jJx9zfU5wVAjSQuBRwykYbSUywsS3GPEbfgFlMDAW0Cls4lbtPqw=="],
"@firecrawl/pdf-inspector-win32-x64-msvc": ["@firecrawl/pdf-inspector-win32-x64-msvc@1.11.1", "", { "os": "win32", "cpu": "x64" }, "sha512-B3hpMRHlJFaOdZaWiG0wyGcfVkf3AQh232tRd0kN4EpAIyo/sEU6+cbEarH1Z+ypd7QRNlO6fcnSYHelZaqS0A=="],
"@inquirer/ansi": ["@inquirer/ansi@2.0.4", "", {}, "sha512-DpcZrQObd7S0R/U3bFdkcT5ebRwbTTC4D3tCc1vsJizmgPLxNJBo+AAFmrZwe8zk30P2QzgzGWZ3Q9uJwWuhIg=="], "@inquirer/ansi": ["@inquirer/ansi@2.0.4", "", {}, "sha512-DpcZrQObd7S0R/U3bFdkcT5ebRwbTTC4D3tCc1vsJizmgPLxNJBo+AAFmrZwe8zk30P2QzgzGWZ3Q9uJwWuhIg=="],
"@inquirer/checkbox": ["@inquirer/checkbox@5.1.2", "", { "dependencies": { "@inquirer/ansi": "^2.0.4", "@inquirer/core": "^11.1.7", "@inquirer/figures": "^2.0.4", "@inquirer/type": "^4.0.4" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-PubpMPO2nJgMufkoB3P2wwxNXEMUXnBIKi/ACzDUYfaoPuM7gSTmuxJeMscoLVEsR4qqrCMf5p0SiYGWnVJ8kw=="], "@inquirer/checkbox": ["@inquirer/checkbox@5.1.2", "", { "dependencies": { "@inquirer/ansi": "^2.0.4", "@inquirer/core": "^11.1.7", "@inquirer/figures": "^2.0.4", "@inquirer/type": "^4.0.4" }, "peerDependencies": { "@types/node": ">=18" }, "optionalPeers": ["@types/node"] }, "sha512-PubpMPO2nJgMufkoB3P2wwxNXEMUXnBIKi/ACzDUYfaoPuM7gSTmuxJeMscoLVEsR4qqrCMf5p0SiYGWnVJ8kw=="],
+1 -3
View File
@@ -153,9 +153,7 @@ fn to_napi_result(r: pdf_inspector::PdfProcessResult) -> PdfResult {
} }
} }
fn to_napi_page_ocr_reasons( fn to_napi_page_ocr_reasons(reasons: Vec<pdf_inspector::PageOcrReasons>) -> Vec<PageOcrReasons> {
reasons: Vec<pdf_inspector::PageOcrReasons>,
) -> Vec<PageOcrReasons> {
reasons reasons
.into_iter() .into_iter()
.map(|reason| PageOcrReasons { .map(|reason| PageOcrReasons {
+1 -1
View File
@@ -11,7 +11,7 @@ import {
extractPagesMarkdown, extractPagesMarkdown,
} from './index.js'; } from './index.js';
const fixture = readFileSync('../tests/fixtures/thermo-freon12.pdf'); const fixture = readFileSync('../../tests/fixtures/thermo-freon12.pdf');
// --- processPdf --- // --- processPdf ---
console.log('Testing processPdf...'); console.log('Testing processPdf...');
+18
View File
@@ -0,0 +1,18 @@
[package]
name = "pdf-inspector-python"
version = "0.2.5"
edition = "2021"
authors = ["Firecrawl Team"]
description = "Python bindings for pdf-inspector"
license = "MIT"
repository = "https://github.com/firecrawl/pdf-inspector"
readme = "README.md"
publish = false
[lib]
name = "pdf_inspector"
crate-type = ["cdylib"]
[dependencies]
pdf-inspector = { path = "../.." }
pyo3 = { version = "0.25", features = ["extension-module", "abi3-py38"] }
@@ -36,6 +36,7 @@ Prebuilt wheels cover CPython ≥3.8 on Linux (x86_64, aarch64), macOS (Intel, A
```bash ```bash
pip install maturin pip install maturin
cd bindings/python
maturin develop --release maturin develop --release
``` ```
@@ -5,10 +5,10 @@ build-backend = "maturin"
[project] [project]
name = "pdf-inspector" name = "pdf-inspector"
# Bump this to publish to PyPI — CI publishes automatically when the version # Bump this to publish to PyPI — CI publishes automatically when the version
# changes on main (same flow as napi/package.json for npm). # changes on main (same flow as bindings/node/package.json for npm).
version = "0.2.5" version = "0.2.5"
description = "Fast PDF inspection, classification, and text extraction with smart scanned vs text-based detection" description = "Fast PDF inspection, classification, and text extraction with smart scanned vs text-based detection"
readme = "docs/python.md" readme = "README.md"
license = { text = "MIT" } license = { text = "MIT" }
requires-python = ">=3.8" requires-python = ">=3.8"
classifiers = [ classifiers = [
@@ -23,7 +23,8 @@ classifiers = [
[project.urls] [project.urls]
Homepage = "https://github.com/firecrawl/pdf-inspector" Homepage = "https://github.com/firecrawl/pdf-inspector"
Repository = "https://github.com/firecrawl/pdf-inspector" Repository = "https://github.com/firecrawl/pdf-inspector"
Documentation = "https://github.com/firecrawl/pdf-inspector/blob/main/docs/python.md" Documentation = "https://github.com/firecrawl/pdf-inspector/blob/main/bindings/python/README.md"
[tool.maturin] [tool.maturin]
features = ["python"] bindings = "pyo3"
module-name = "pdf_inspector"
+25 -24
View File
@@ -4,8 +4,9 @@ use pyo3::exceptions::PyValueError;
use pyo3::prelude::*; use pyo3::prelude::*;
use std::collections::HashSet; use std::collections::HashSet;
use crate::detector::PdfType; use ::pdf_inspector as core;
use crate::types::ItemType; use core::detector::PdfType;
use core::types::ItemType;
// --------------------------------------------------------------------------- // ---------------------------------------------------------------------------
// Result wrapper // Result wrapper
@@ -299,7 +300,7 @@ fn pdf_type_str(t: PdfType) -> String {
} }
} }
fn to_py_result(r: crate::PdfProcessResult) -> PyPdfResult { fn to_py_result(r: core::PdfProcessResult) -> PyPdfResult {
PyPdfResult { PyPdfResult {
pdf_type: pdf_type_str(r.pdf_type), pdf_type: pdf_type_str(r.pdf_type),
markdown: r.markdown, markdown: r.markdown,
@@ -316,7 +317,7 @@ fn to_py_result(r: crate::PdfProcessResult) -> PyPdfResult {
} }
} }
fn to_py_page_ocr_reasons(reasons: Vec<crate::PageOcrReasons>) -> Vec<PyPageOcrReasons> { fn to_py_page_ocr_reasons(reasons: Vec<core::PageOcrReasons>) -> Vec<PyPageOcrReasons> {
reasons reasons
.into_iter() .into_iter()
.map(|reason| PyPageOcrReasons { .map(|reason| PyPageOcrReasons {
@@ -326,7 +327,7 @@ fn to_py_page_ocr_reasons(reasons: Vec<crate::PageOcrReasons>) -> Vec<PyPageOcrR
.collect() .collect()
} }
fn to_py_err(e: crate::PdfError) -> PyErr { fn to_py_err(e: core::PdfError) -> PyErr {
PyValueError::new_err(e.to_string()) PyValueError::new_err(e.to_string())
} }
@@ -339,7 +340,7 @@ fn item_type_str(t: &ItemType) -> String {
} }
} }
fn convert_text_items(items: Vec<crate::TextItem>) -> Vec<PyTextItem> { fn convert_text_items(items: Vec<core::TextItem>) -> Vec<PyTextItem> {
items items
.into_iter() .into_iter()
.map(|item| PyTextItem { .map(|item| PyTextItem {
@@ -392,7 +393,7 @@ fn parse_page_regions(
.collect() .collect()
} }
fn to_py_pages_result(r: crate::PagesExtractionResult) -> PyPagesExtractionResult { fn to_py_pages_result(r: core::PagesExtractionResult) -> PyPagesExtractionResult {
PyPagesExtractionResult { PyPagesExtractionResult {
pages: r pages: r
.pages .pages
@@ -412,7 +413,7 @@ fn to_py_pages_result(r: crate::PagesExtractionResult) -> PyPagesExtractionResul
} }
} }
fn convert_region_results(results: Vec<crate::PageRegionResult>) -> Vec<PyPageRegionTexts> { fn convert_region_results(results: Vec<core::PageRegionResult>) -> Vec<PyPageRegionTexts> {
results results
.into_iter() .into_iter()
.map(|page_result| PyPageRegionTexts { .map(|page_result| PyPageRegionTexts {
@@ -438,11 +439,11 @@ fn convert_region_results(results: Vec<crate::PageRegionResult>) -> Vec<PyPageRe
#[pyfunction] #[pyfunction]
#[pyo3(signature = (path, pages=None))] #[pyo3(signature = (path, pages=None))]
fn process_pdf(path: &str, pages: Option<Vec<u32>>) -> PyResult<PyPdfResult> { fn process_pdf(path: &str, pages: Option<Vec<u32>>) -> PyResult<PyPdfResult> {
let mut opts = crate::PdfOptions::new(); let mut opts = core::PdfOptions::new();
if let Some(p) = pages { if let Some(p) = pages {
opts = opts.pages(p); opts = opts.pages(p);
} }
let result = crate::process_pdf_with_options(path, opts).map_err(to_py_err)?; let result = core::process_pdf_with_options(path, opts).map_err(to_py_err)?;
Ok(to_py_result(result)) Ok(to_py_result(result))
} }
@@ -450,25 +451,25 @@ fn process_pdf(path: &str, pages: Option<Vec<u32>>) -> PyResult<PyPdfResult> {
#[pyfunction] #[pyfunction]
#[pyo3(signature = (data, pages=None))] #[pyo3(signature = (data, pages=None))]
fn process_pdf_bytes(data: &[u8], pages: Option<Vec<u32>>) -> PyResult<PyPdfResult> { fn process_pdf_bytes(data: &[u8], pages: Option<Vec<u32>>) -> PyResult<PyPdfResult> {
let mut opts = crate::PdfOptions::new(); let mut opts = core::PdfOptions::new();
if let Some(p) = pages { if let Some(p) = pages {
opts = opts.pages(p); opts = opts.pages(p);
} }
let result = crate::process_pdf_mem_with_options(data, opts).map_err(to_py_err)?; let result = core::process_pdf_mem_with_options(data, opts).map_err(to_py_err)?;
Ok(to_py_result(result)) Ok(to_py_result(result))
} }
/// Fast detection only — no text extraction or markdown. /// Fast detection only — no text extraction or markdown.
#[pyfunction] #[pyfunction]
fn detect_pdf(path: &str) -> PyResult<PyPdfResult> { fn detect_pdf(path: &str) -> PyResult<PyPdfResult> {
let result = crate::detect_pdf(path).map_err(to_py_err)?; let result = core::detect_pdf(path).map_err(to_py_err)?;
Ok(to_py_result(result)) Ok(to_py_result(result))
} }
/// Fast detection from bytes — no text extraction or markdown. /// Fast detection from bytes — no text extraction or markdown.
#[pyfunction] #[pyfunction]
fn detect_pdf_bytes(data: &[u8]) -> PyResult<PyPdfResult> { fn detect_pdf_bytes(data: &[u8]) -> PyResult<PyPdfResult> {
let result = crate::detect_pdf_mem(data).map_err(to_py_err)?; let result = core::detect_pdf_mem(data).map_err(to_py_err)?;
Ok(to_py_result(result)) Ok(to_py_result(result))
} }
@@ -485,7 +486,7 @@ fn classify_pdf(path: &str) -> PyResult<PyPdfClassification> {
/// Pages in pages_needing_ocr are 0-indexed. /// Pages in pages_needing_ocr are 0-indexed.
#[pyfunction] #[pyfunction]
fn classify_pdf_bytes(data: &[u8]) -> PyResult<PyPdfClassification> { fn classify_pdf_bytes(data: &[u8]) -> PyResult<PyPdfClassification> {
let result = crate::classify_pdf_mem(data).map_err(to_py_err)?; let result = core::classify_pdf_mem(data).map_err(to_py_err)?;
Ok(PyPdfClassification { Ok(PyPdfClassification {
pdf_type: pdf_type_str(result.pdf_type), pdf_type: pdf_type_str(result.pdf_type),
page_count: result.page_count, page_count: result.page_count,
@@ -497,13 +498,13 @@ fn classify_pdf_bytes(data: &[u8]) -> PyResult<PyPdfClassification> {
/// Extract plain text from a PDF file. /// Extract plain text from a PDF file.
#[pyfunction] #[pyfunction]
fn extract_text(path: &str) -> PyResult<String> { fn extract_text(path: &str) -> PyResult<String> {
crate::extract_text(path).map_err(to_py_err) core::extract_text(path).map_err(to_py_err)
} }
/// Extract plain text from PDF bytes. /// Extract plain text from PDF bytes.
#[pyfunction] #[pyfunction]
fn extract_text_bytes(data: &[u8]) -> PyResult<String> { fn extract_text_bytes(data: &[u8]) -> PyResult<String> {
crate::extractor::extract_text_mem(data).map_err(to_py_err) core::extractor::extract_text_mem(data).map_err(to_py_err)
} }
/// Extract text with position information from a file. /// Extract text with position information from a file.
@@ -513,9 +514,9 @@ fn extract_text_with_positions(path: &str, pages: Option<Vec<u32>>) -> PyResult<
let items = match pages { let items = match pages {
Some(p) => { Some(p) => {
let page_set: HashSet<u32> = p.into_iter().collect(); let page_set: HashSet<u32> = p.into_iter().collect();
crate::extract_text_with_positions_pages(path, Some(&page_set)).map_err(to_py_err)? core::extract_text_with_positions_pages(path, Some(&page_set)).map_err(to_py_err)?
} }
None => crate::extract_text_with_positions(path).map_err(to_py_err)?, None => core::extract_text_with_positions(path).map_err(to_py_err)?,
}; };
Ok(convert_text_items(items)) Ok(convert_text_items(items))
} }
@@ -530,10 +531,10 @@ fn extract_text_with_positions_bytes(
let items = match pages { let items = match pages {
Some(p) => { Some(p) => {
let page_set: HashSet<u32> = p.into_iter().collect(); let page_set: HashSet<u32> = p.into_iter().collect();
crate::extractor::extract_text_with_positions_mem_pages(data, Some(&page_set)) core::extractor::extract_text_with_positions_mem_pages(data, Some(&page_set))
.map_err(to_py_err)? .map_err(to_py_err)?
} }
None => crate::extractor::extract_text_with_positions_mem(data).map_err(to_py_err)?, None => core::extractor::extract_text_with_positions_mem(data).map_err(to_py_err)?,
}; };
Ok(convert_text_items(items)) Ok(convert_text_items(items))
} }
@@ -571,7 +572,7 @@ fn extract_text_in_regions_bytes(
page_regions: Vec<(u32, Vec<Vec<f64>>)>, page_regions: Vec<(u32, Vec<Vec<f64>>)>,
) -> PyResult<Vec<PyPageRegionTexts>> { ) -> PyResult<Vec<PyPageRegionTexts>> {
let regions = parse_page_regions(page_regions)?; let regions = parse_page_regions(page_regions)?;
let results = crate::extract_text_in_regions_mem(data, &regions).map_err(to_py_err)?; let results = core::extract_text_in_regions_mem(data, &regions).map_err(to_py_err)?;
Ok(convert_region_results(results)) Ok(convert_region_results(results))
} }
@@ -596,7 +597,7 @@ fn extract_pages_markdown(
path: &str, path: &str,
pages: Option<Vec<u32>>, pages: Option<Vec<u32>>,
) -> PyResult<PyPagesExtractionResult> { ) -> PyResult<PyPagesExtractionResult> {
let result = crate::extract_pages_markdown(path, pages.as_deref()).map_err(to_py_err)?; let result = core::extract_pages_markdown(path, pages.as_deref()).map_err(to_py_err)?;
Ok(to_py_pages_result(result)) Ok(to_py_pages_result(result))
} }
@@ -609,7 +610,7 @@ fn extract_pages_markdown_bytes(
data: &[u8], data: &[u8],
pages: Option<Vec<u32>>, pages: Option<Vec<u32>>,
) -> PyResult<PyPagesExtractionResult> { ) -> PyResult<PyPagesExtractionResult> {
let result = crate::extract_pages_markdown_mem(data, pages.as_deref()).map_err(to_py_err)?; let result = core::extract_pages_markdown_mem(data, pages.as_deref()).map_err(to_py_err)?;
Ok(to_py_pages_result(result)) Ok(to_py_pages_result(result))
} }
@@ -1,14 +1,16 @@
"""Tests for the pdf_inspector Python bindings.""" """Tests for the pdf_inspector Python bindings."""
import os import os
from pathlib import Path
import pytest import pytest
import pdf_inspector import pdf_inspector
FIXTURES_DIR = os.path.join(os.path.dirname(__file__), "fixtures") FIXTURES_DIR = Path(__file__).resolve().parents[3] / "tests" / "fixtures"
def fixture_path(name: str) -> str: def fixture_path(name: str) -> str:
return os.path.join(FIXTURES_DIR, name) return str(FIXTURES_DIR / name)
def fixture_bytes(name: str) -> bytes: def fixture_bytes(name: str) -> bytes:
@@ -389,7 +391,11 @@ class TestMultipleFixtures:
@pytest.mark.parametrize( @pytest.mark.parametrize(
"filename", "filename",
[f for f in os.listdir(FIXTURES_DIR) if f.endswith(".pdf")], [
f
for f in os.listdir(FIXTURES_DIR)
if f.endswith(".pdf") and f != "encrypted-secret123.pdf"
],
) )
def test_process_all_fixtures(self, filename): def test_process_all_fixtures(self, filename):
result = pdf_inspector.process_pdf(fixture_path(filename)) result = pdf_inspector.process_pdf(fixture_path(filename))
@@ -401,3 +407,7 @@ class TestMultipleFixtures:
) )
assert result.page_count > 0 assert result.page_count > 0
assert result.confidence >= 0.0 assert result.confidence >= 0.0
def test_password_protected_fixture_reports_error(self):
with pytest.raises(ValueError, match="encrypted"):
pdf_inspector.process_pdf(fixture_path("encrypted-secret123.pdf"))
+1 -7
View File
@@ -16,7 +16,7 @@ crate-type = ["cdylib", "rlib"]
[dependencies] [dependencies]
console_error_panic_hook = "0.1" console_error_panic_hook = "0.1"
js-sys = "0.3" js-sys = "0.3"
pdf-inspector = { path = ".." } pdf-inspector = { path = "../.." }
serde = { version = "1", features = ["derive"] } serde = { version = "1", features = ["derive"] }
serde-wasm-bindgen = "0.6" serde-wasm-bindgen = "0.6"
wasm-bindgen = "0.2" wasm-bindgen = "0.2"
@@ -24,12 +24,6 @@ wasm-bindgen = "0.2"
[dev-dependencies] [dev-dependencies]
wasm-bindgen-test = "0.3" wasm-bindgen-test = "0.3"
[profile.release]
codegen-units = 1
lto = true
opt-level = "s"
strip = true
[package.metadata.wasm-pack.profile.release] [package.metadata.wasm-pack.profile.release]
# Rust 1.95 emits bulk-memory instructions that the binaryen bundled with # Rust 1.95 emits bulk-memory instructions that the binaryen bundled with
# wasm-pack 0.15.0 does not yet validate. rustc still performs the release, # wasm-pack 0.15.0 does not yet validate. rustc still performs the release,
+1 -1
View File
@@ -52,7 +52,7 @@ The package also exports:
```bash ```bash
cargo install wasm-pack --version 0.15.0 --locked cargo install wasm-pack --version 0.15.0 --locked
wasm-pack build wasm --target web --scope firecrawl --release wasm-pack build bindings/wasm --target web --scope firecrawl --profile wasm-release --no-opt
``` ```
## License ## License
+2 -2
View File
@@ -292,8 +292,8 @@ mod tests {
use js_sys::Reflect; use js_sys::Reflect;
use wasm_bindgen_test::*; use wasm_bindgen_test::*;
const TEXT_PDF: &[u8] = include_bytes!("../../tests/fixtures/thermo-freon12.pdf"); const TEXT_PDF: &[u8] = include_bytes!("../../../tests/fixtures/thermo-freon12.pdf");
const ENCRYPTED_PDF: &[u8] = include_bytes!("../../tests/fixtures/encrypted-secret123.pdf"); const ENCRYPTED_PDF: &[u8] = include_bytes!("../../../tests/fixtures/encrypted-secret123.pdf");
fn synthetic_korea1_pdf() -> Vec<u8> { fn synthetic_korea1_pdf() -> Vec<u8> {
let mut pdf = b"%PDF-1.4\n".to_vec(); let mut pdf = b"%PDF-1.4\n".to_vec();
+5 -5
View File
@@ -22,17 +22,17 @@ If `Cargo.toml` changes without a package version bump, the workflow exits witho
## Browser WebAssembly package ## Browser WebAssembly package
The browser package is published as `@firecrawl/pdf-inspector-wasm`. Its version lives in `wasm/Cargo.toml`, and `.github/workflows/publish-wasm.yml` builds the `web` target with `wasm-pack` before publishing the generated package. The browser package is published as `@firecrawl/pdf-inspector-wasm`. Its version lives in `bindings/wasm/Cargo.toml`, and `.github/workflows/publish-wasm.yml` builds the `web` target with `wasm-pack` before publishing the generated package.
The npm package must exist before a trusted publisher can be configured. For the first release only: The npm package must exist before a trusted publisher can be configured. For the first release only:
1. Build with `wasm-pack build wasm --target web --scope firecrawl --out-dir pkg --release`. 1. Build with `wasm-pack build bindings/wasm --target web --scope firecrawl --out-dir pkg --profile wasm-release --no-opt`.
2. Inspect with `npm pack --dry-run ./wasm/pkg`. 2. Inspect with `npm pack --dry-run ./bindings/wasm/pkg`.
3. Publish with `npm publish ./wasm/pkg --access public` from an authorized maintainer session. 3. Publish with `npm publish ./bindings/wasm/pkg --access public` from an authorized maintainer session.
4. In the package settings on npm, configure the GitHub Actions trusted publisher: 4. In the package settings on npm, configure the GitHub Actions trusted publisher:
- Organization: `firecrawl` - Organization: `firecrawl`
- Repository: `pdf-inspector` - Repository: `pdf-inspector`
- Workflow: `publish-wasm.yml` - Workflow: `publish-wasm.yml`
- Allowed action: `npm publish` - Allowed action: `npm publish`
After that one-time bootstrap, bumping the version in `wasm/Cargo.toml` and merging it to `main` publishes through OIDC. Until the package exists, the workflow exits cleanly without attempting an unauthenticated first publish. See npm's [trusted publishing documentation](https://docs.npmjs.com/trusted-publishers/) for the registry-side setup. After that one-time bootstrap, bumping the version in `bindings/wasm/Cargo.toml` and merging it to `main` publishes through OIDC. Until the package exists, the workflow exits cleanly without attempting an unauthenticated first publish. See npm's [trusted publishing documentation](https://docs.npmjs.com/trusted-publishers/) for the registry-side setup.
-6
View File
@@ -1,6 +0,0 @@
target/
node_modules/
*.node
# Override root .gitignore — lock file needed for reproducible napi builds
!Cargo.lock
+4 -4
View File
@@ -802,7 +802,7 @@
<p>Emit headings, lists, tables, links, code, emphasis, captions, page markers, and token-efficient cleanup.</p> <p>Emit headings, lists, tables, links, code, emphasis, captions, page markers, and token-efficient cleanup.</p>
</article> </article>
<article class="capability"> <article class="capability">
<div class="cap-id"><span>06</span><span>napi/</span></div> <div class="cap-id"><span>06</span><span>bindings/</span></div>
<h3>Packaged for your stack</h3> <h3>Packaged for your stack</h3>
<p>Install from npm, PyPI, or crates.io. The npm package also includes TypeScript definitions and the bundled pdf-inspector CLI.</p> <p>Install from npm, PyPI, or crates.io. The npm package also includes TypeScript definitions and the bundled pdf-inspector CLI.</p>
</article> </article>
@@ -915,7 +915,7 @@
console.<span class="fn">log</span>(result.pdfType); console.<span class="fn">log</span>(result.pdfType);
console.<span class="fn">log</span>(result.markdown); console.<span class="fn">log</span>(result.markdown);
<span class="cm">// </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/napi/README.md">Full Node.js API reference ↗</a></pre></div> <span class="cm">// </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/bindings/node/README.md">Full Node.js API reference ↗</a></pre></div>
<div class="code-panel" id="panel-cli" role="tabpanel"><pre><span class="cm"># run directly from npm</span> <div class="code-panel" id="panel-cli" role="tabpanel"><pre><span class="cm"># run directly from npm</span>
npx <span class="fn">@firecrawl/pdf-inspector</span> document.pdf npx <span class="fn">@firecrawl/pdf-inspector</span> document.pdf
@@ -929,7 +929,7 @@ npm install -g <span class="fn">@firecrawl/pdf-inspector</span>
<span class="cm"># classification only</span> <span class="cm"># classification only</span>
<span class="fn">pdf-inspector</span> detect document.pdf --json <span class="fn">pdf-inspector</span> detect document.pdf --json
<span class="cm"># </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/napi/README.md">Node.js and CLI reference ↗</a></pre></div> <span class="cm"># </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/bindings/node/README.md">Node.js and CLI reference ↗</a></pre></div>
<div class="code-panel" id="panel-python" role="tabpanel"><pre><span class="cm"># pip install pdf-inspector</span> <div class="code-panel" id="panel-python" role="tabpanel"><pre><span class="cm"># pip install pdf-inspector</span>
<span class="kw">import</span> pdf_inspector <span class="kw">import</span> pdf_inspector
@@ -939,7 +939,7 @@ result = pdf_inspector.<span class="fn">process_pdf</span>(<span class="str">"do
<span class="fn">print</span>(result.markdown) <span class="fn">print</span>(result.markdown)
<span class="fn">print</span>(result.pages_needing_ocr) <span class="fn">print</span>(result.pages_needing_ocr)
<span class="cm"># </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/docs/python.md">Full Python API reference ↗</a></pre></div> <span class="cm"># </span><a href="https://github.com/firecrawl/pdf-inspector/blob/main/bindings/python/README.md">Full Python API reference ↗</a></pre></div>
<div class="code-panel" id="panel-rust" role="tabpanel"><pre><span class="cm">// cargo add pdf-inspector</span> <div class="code-panel" id="panel-rust" role="tabpanel"><pre><span class="cm">// cargo add pdf-inspector</span>
<span class="kw">use</span> pdf_inspector::process_pdf; <span class="kw">use</span> pdf_inspector::process_pdf;
-3
View File
@@ -28,9 +28,6 @@
//! ).unwrap(); //! ).unwrap();
//! ``` //! ```
#[cfg(feature = "python")]
pub mod python;
pub mod adobe_korea1; pub mod adobe_korea1;
pub mod detector; pub mod detector;
pub mod extractor; pub mod extractor;
-1304
View File
File diff suppressed because it is too large Load Diff