### Install cargo-release Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/releasing.md Install the `cargo-release` tool globally. This is a one-time setup. ```bash cargo install cargo-release --locked ``` -------------------------------- ### Start Demo Development Server Source: https://github.com/fabifont/open-redact-pdf/blob/main/README.md Starts the development server for the demo application, allowing for live updates and testing. ```bash just dev ``` -------------------------------- ### Install Dependencies Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/getting-started.md Installs project dependencies using pnpm. ```bash pnpm install ``` -------------------------------- ### Run the Demo Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/getting-started.md Starts the development server for the open-redact-pdf-demo-web package. ```bash pnpm --filter open-redact-pdf-demo-web dev ``` -------------------------------- ### Install Open Redact PDF TS SDK Source: https://github.com/fabifont/open-redact-pdf/blob/main/packages/ts-sdk/README.md Install the SDK using npm. ```bash npm install @fabifont/open-redact-pdf ``` -------------------------------- ### Install JS Dependencies Source: https://github.com/fabifont/open-redact-pdf/blob/main/README.md Installs JavaScript dependencies for the project. Run this command before other build or development commands. ```bash just install ``` -------------------------------- ### Full PDF redaction workflow example Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/ts-sdk.md Demonstrates initializing the WASM module, opening a PDF, searching for text, applying redactions, and saving the sanitized PDF. This example redacts 'account' occurrences, strips metadata and attachments, and uses the default redaction mode. ```typescript import { initWasm, openPdf, freePdf, searchText, applyRedactions, savePdf, } from "@fabifont/open-redact-pdf" await initWasm() const handle = openPdf(bytes) const matches = searchText(handle, 0, "account") const targets = matches.map((match) => ({ kind: "quadGroup" as const, pageIndex: match.pageIndex, quads: match.quads, })) applyRedactions(handle, { targets, mode: "redact", stripMetadata: true, stripAttachments: true, }) const sanitized = savePdf(handle) ``` -------------------------------- ### Rust - Apply Redactions Example Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/rust-api.md Demonstrates how to open a PDF, search for text, define redaction targets based on search results, apply redactions using a specified mode, and save the modified document. Ensure the necessary types are imported. ```rust use open_redact_pdf::{PdfDocument, RedactionMode, RedactionPlan, RedactionTarget}; let mut document = PdfDocument::open(&bytes)?; let matches = document.search_text(0, "account")?; let targets = matches .into_iter() .map(|match_| RedactionTarget::QuadGroup { page_index: match_.page_index, quads: match_.quads.into_iter().map(|quad| quad.points).collect(), }) .collect(); document.apply_redactions(RedactionPlan { targets, mode: Some(RedactionMode::Redact), fill_color: None, overlay_text: None, remove_intersecting_annotations: Some(true), strip_metadata: Some(true), strip_attachments: Some(true), })?; let output = document.save()?; # Ok::<(), Box>(()) ``` -------------------------------- ### ToUnicode CMap Example Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Demonstrates the syntax for mapping glyph codes to Unicode strings using beginbfchar and endbfchar directives. ```postscript beginbfchar <0041> <0041> % CID 0x41 → U+0041 'A' endbfchar beginbfrange <0020> <0039> <0020> % CIDs 0x20–0x39 map linearly from U+0020 endbfrange ``` -------------------------------- ### Matrix Multiplication Example Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/05-graphics-state.md Demonstrates matrix multiplication for combining transformations. This is used in PDF processing to compute the final transformation of graphical elements. ```rust M2 = { a:3.125, b:0, c:0, d:3.125, e:0, f:0 } CTM = M2.multiply(M1) = { a:0.75, b:0, c:0, d:-0.75, e:0, f:841.92 } ``` -------------------------------- ### Minimal Rust Example for PDF Redaction Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/getting-started.md Demonstrates how to open a PDF, apply redactions by rectangle, and save the sanitized PDF using the Rust SDK. Strips metadata and attachments. ```rust use open_redact_pdf::{PdfDocument, RedactionPlan, RedactionTarget}; let bytes = std::fs::read("input.pdf")?; let mut document = PdfDocument::open(&bytes)?; let report = document.apply_redactions(RedactionPlan { targets: vec![RedactionTarget::Rect { page_index: 0, x: 72.0, y: 500.0, width: 120.0, height: 18.0, }], fill_color: None, overlay_text: None, remove_intersecting_annotations: Some(true), strip_metadata: Some(true), strip_attachments: Some(true), })?; let sanitized = document.save()?; std::fs::write("sanitized.pdf", sanitized)?; println!("{report:?}"); # Ok::<(), Box>(()) ``` -------------------------------- ### Invoking an XObject Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Example of how an XObject is invoked by name from the Resources dictionary using the 'Do' operator. ```postscript /Logo Do ``` -------------------------------- ### PDF File Structure Example Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Illustrates the main sections of a PDF file: header, body, cross-reference table (xref), and trailer. PDF readers process the file from end to beginning. ```plaintext %PDF-1.7 <-- header (version) ...body (objects)... xref <-- cross-reference table 0 N <-- N entries 0000000000 65535 f <-- entry 0 (always free) 0000000009 00000 n <-- entry 1: object 1 at byte offset 9 ... <-- trailer dictionary trailer << /Size N /Root 1 0 R >> <-- trailer dictionary startxref 441 <-- byte offset of xref %%EOF ``` -------------------------------- ### Minimal TypeScript Example for PDF Redaction Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/getting-started.md Shows how to initialize the WASM module, open a PDF, search for text, apply redactions based on search results, and save the redacted PDF using the TypeScript SDK. Strips metadata and attachments. ```typescript import { initWasm, openPdf, searchText, applyRedactions, savePdf, } from "@fabifont/open-redact-pdf"; await initWasm(); const handle = openPdf(inputBytes); const matches = searchText(handle, 0, "account"); applyRedactions(handle, { targets: matches.map((match) => ({ kind: "quadGroup", pageIndex: match.pageIndex, quads: match.quads, })), stripMetadata: true, stripAttachments: true, }); const output = savePdf(handle); ``` -------------------------------- ### Get Page Size Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/ts-sdk.md Returns the normalized page-space size. ```APIDOC ## getPageSize(handle: PdfHandle, pageIndex: number): PageSize ### Description Returns the normalized page-space size. ### Method N/A (Function Call) ### Parameters #### Request Body - **handle** (PdfHandle) - Required - The handle of the PDF document. - **pageIndex** (number) - Required - The index of the page (0-based). ### Response #### Success Response - **PageSize** - An object containing the width and height of the page. #### Response Example ```json { "example": { "width": 612, "height": 792 } } ``` ``` -------------------------------- ### Initialize and Use Open Redact PDF TS SDK Source: https://github.com/fabifont/open-redact-pdf/blob/main/packages/ts-sdk/README.md Initialize the WebAssembly module and use SDK functions to open a PDF and get its page count. Ensure the WebAssembly module is initialized before calling other functions. ```typescript import { initWasm, openPdf, getPageCount } from "@fabifont/open-redact-pdf"; await initWasm(); const handle = openPdf(pdfBytes); const count = getPageCount(handle); ``` -------------------------------- ### TypeScript/WebAssembly SDK for PDF Decryption Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/encrypted-pdfs.md Illustrates how to use the `@fabifont/open-redact-pdf` SDK in TypeScript to open encrypted PDFs. It includes examples for handling password-protected and public-key encrypted files, along with WASM initialization. ```APIDOC ## TypeScript / WebAssembly SDK ### Description This SDK provides functions to interact with the PDF decryption capabilities from JavaScript or TypeScript, leveraging WebAssembly. It supports opening PDFs with passwords and public-key certificates. ### Initialization - **`initWasm()`** Initializes the WebAssembly module. Must be called before using other SDK functions. ### Methods - **`openPdf(bytes: Uint8Array): PdfHandle`** Opens an unencrypted PDF document. - **`openPdfWithPassword(bytes: Uint8Array, password: string): PdfHandle`** Opens a PDF document that requires a password. The password string is converted to UTF-8 bytes before being sent to the WASM engine. - **`openPdfWithCertificate(pdfBytes: Uint8Array, certDer: Uint8Array, keyDer: Uint8Array): PdfHandle`** Opens a public-key encrypted PDF. Requires DER-encoded recipient certificate and PKCS#8 private key. ### Error Handling - The `openPdf` function may throw an error if the PDF is encrypted and requires a password. This error can be caught, and if it indicates an 'invalid password', `openPdfWithPassword` can be called with the correct credentials. ### Usage Notes - For public-key encryption, ensure the certificate and private key are DER-encoded. Conversion from formats like PEM or PKCS#12 might be necessary on the JavaScript side. - The SDK does not persist or transmit the certificate and private key buffers after decryption. ``` -------------------------------- ### Release Project Source: https://github.com/fabifont/open-redact-pdf/blob/main/README.md Manages the release process for the project, including version bumping, dependency updates, committing, tagging, and pushing. Requires 'cargo-release' to be installed. ```bash cargo release ``` -------------------------------- ### Build Project Packages Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/testing-and-fixtures.md Build the main project package and the demo web application using pnpm. These are required checks before merging code. ```bash pnpm --filter @fabifont/open-redact-pdf build ``` ```bash pnpm --filter open-redact-pdf-demo-web build ``` -------------------------------- ### Full Project Build Source: https://github.com/fabifont/open-redact-pdf/blob/main/README.md Performs a full build of the project, including compiling Rust to WebAssembly, generating the TypeScript SDK, and building the demo application. ```bash just build ``` -------------------------------- ### Build Demo Web Application Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/development.md Typecheck and build the web demo application. This command specifically targets the demo package within the pnpm workspace. ```bash pnpm --filter open-redact-pdf-demo-web build ``` -------------------------------- ### Get Page Count Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/ts-sdk.md Returns the page count for the parsed PDF. ```APIDOC ## getPageCount(handle: PdfHandle): number ### Description Returns the page count for the parsed PDF. ### Method N/A (Function Call) ### Parameters #### Request Body - **handle** (PdfHandle) - Required - The handle of the PDF document. ### Response #### Success Response - **number** - The total number of pages in the PDF. #### Response Example ```json { "example": 10 } ``` ``` -------------------------------- ### PdfDocument::page_size Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/rust-api.md Gets the dimensions (width and height) of a specific page. ```APIDOC ## PdfDocument::page_size ### Description Retrieves the dimensions (width and height) of a specified page in the PDF document. ### Method Rust method call ### Signature `page_size(&self, page_index: usize) -> PdfResult` ### Parameters #### Path Parameters None #### Query Parameters None #### Request Body * **page_index** (`usize`) - Required - The zero-based index of the page for which to get the size. ### Request Example ```rust let size = document.page_size(0)?; ``` ### Response #### Success Response - **PageSize** (`PageSize`) - An object containing the `width` and `height` of the page in normalized PDF units. #### Response Example ```json { "width": 612.0, "height": 792.0 } ``` ### Errors - `PdfError` - If the `page_index` is invalid or other errors occur. ``` -------------------------------- ### Basic PDF Content Stream Operations Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Demonstrates setting line width, moving to a position, drawing a line, and showing text using PDF operators in postfix notation. ```pdf % Set line width to 2 points 2 w % Move to (100, 700), draw line to (200, 700), stroke it 100 700 m 200 700 l S % Show text at position (72, 600), 12-point Helvetica /Helvetica 12 Tf 72 600 Td (Hello, PDF) Tj ``` -------------------------------- ### Rust WASM build process Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/11-wasm-boundary.md Illustrates the build pipeline from Rust crates to a JavaScript-compatible WASM module using wasm-pack. ```text Rust crates (open_redact_pdf, pdf_*) ↓ wasm-pack --target bundler pdf_wasm crate (wasm_api.rs) ↓ wasm-bindgen generates packages/ts-sdk/vendor/pdf-wasm/ (JS glue + .wasm binary) ↓ dynamic import() packages/ts-sdk/src/index.ts ↓ workspace dependency apps/demo-web/ ``` -------------------------------- ### Test Demo Web Application Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/testing-and-fixtures.md Run tests for the demo web application using pnpm. This is a required check before merging code. ```bash pnpm --filter open-redact-pdf-demo-web test ``` -------------------------------- ### Graphics State Management with q and Q Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Illustrates how to push and pop the graphics state using 'q' and 'Q' operators to isolate drawing operations, such as drawing a filled rectangle with a specific gray color. ```pdf q 0.5 g % set fill gray to 50% 100 100 200 50 re f % draw a filled rectangle Q % restore previous fill color ``` -------------------------------- ### Initialization Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/ts-sdk.md Loads the generated wasm module. Call this once before opening PDFs. ```APIDOC ## initWasm(): Promise ### Description Loads the generated wasm module. Call this once before opening PDFs. ### Method N/A (Function Call) ### Parameters None ### Response #### Success Response - **void** - Indicates successful loading of the WASM module. #### Response Example N/A (Promise resolves with no value) ``` -------------------------------- ### PDF Xref Table with Multiple Subsections Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Shows a PDF cross-reference table containing multiple subsections, used when objects are not numbered consecutively. Each subsection starts with an 'xref' keyword. ```plaintext xref 0 1 0000000000 65535 f 5 3 0000000123 00000 n 0000000234 00000 n 0000000345 00000 n ``` -------------------------------- ### Example Canonical Target Model JSON Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/target-model.md This JSON structure defines a list of targets for redaction. It includes a rectangle target and a quad-group target, specifying their kind, page index, and geometric coordinates. ```json { "targets": [ { "kind": "rect", "pageIndex": 0, "x": 72, "y": 500, "width": 120, "height": 18 }, { "kind": "quadGroup", "pageIndex": 0, "quads": [ [ { "x": 320, "y": 530 }, { "x": 378, "y": 530 }, { "x": 378, "y": 544 }, { "x": 320, "y": 544 } ] ] } ] } ``` -------------------------------- ### Verify Workspace and Build Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/getting-started.md Runs tests, lints the code, and builds the WASM modules for the workspace and specific packages. ```bash cargo test --workspace cargo clippy --workspace --all-targets -- -D warnings pnpm wasm:build pnpm --filter @fabifont/open-redact-pdf build pnpm --filter open-redact-pdf-demo-web build pnpm --filter open-redact-pdf-demo-web test ``` -------------------------------- ### Build and Development Commands for Open Redact PDF Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/browser-integration.md Commands to rebuild the WebAssembly module and run the development server for the Open Redact PDF project and its demo. ```bash pnpm wasm:build pnpm --filter @fabifont/open-redact-pdf build pnpm --filter open-redact-pdf-demo-web dev ``` -------------------------------- ### Tagging a Release for Publishing Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/publishing.md Use this command to create a Git tag that triggers the release workflow for publishing packages. ```bash git tag v0.1.0 git push origin v0.1.0 ``` -------------------------------- ### Check release version manually Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/releasing.md Before pushing a tag manually, run this command to verify that all version manifests are consistent. This helps catch mismatches locally. ```bash node scripts/check-release-version.mjs v$NEW_VERSION ``` -------------------------------- ### PDF Text Analysis Entry Point Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/01-architecture-overview.md This function is the entry point for analyzing page text in a PDF file. It decompresses and parses the content stream, interpreting operators to extract glyph information. ```rust pdf_text::analyze_page_text(file: &PdfFile, page_index: usize, page: &PageInfo) ``` -------------------------------- ### Generate Fixtures Script Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/testing-and-fixtures.md Use this Node.js script to generate the fixture PDFs for testing. Ensure generated PDFs and the generator script remain synchronized. ```bash node tests/fixtures/generate-fixtures.mjs ``` -------------------------------- ### Run All Tests Source: https://github.com/fabifont/open-redact-pdf/blob/main/README.md Executes all tests within the project to ensure functionality and stability. ```bash just test ``` -------------------------------- ### Public Entry Point for PDF Parsing Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/03-parsing-model.md The `parse_pdf` function is the sole public entry point for parsing. It takes a byte slice and returns a `ParsedDocument` containing the parsed object table, trailer, and page tree. All other parsing functions are internal details. ```rust pub fn parse_pdf(bytes: &[u8]) -> Result ``` -------------------------------- ### Open PDF Document (Rust) Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/encrypted-pdfs.md Use `PdfDocument::open` for unencrypted or empty-password protected documents. For documents requiring a password, use `PdfDocument::open_with_password`. ```rust use open_redact_pdf::PdfDocument; // Empty-password (or unencrypted) documents. let document = PdfDocument::open(&bytes)?; // Documents that need a non-empty user or owner password. let document = PdfDocument::open_with_password(&bytes, b"secret")?; ``` -------------------------------- ### Parse PDF Document Bytes Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/01-architecture-overview.md Initiates the PDF parsing process by taking a byte slice as input. This is the entry point for reading a PDF file into the system. ```rust pdf_objects::parse_pdf(bytes: &[u8]) ``` -------------------------------- ### Rust Facade for PDF Decryption Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/encrypted-pdfs.md Demonstrates how to open encrypted PDF documents using the Rust `PdfDocument` API. It covers opening unencrypted documents, documents with passwords, and public-key encrypted documents. ```APIDOC ## Rust Facade ### Description Use the `PdfDocument` struct to open and process PDF files. This API supports opening unencrypted documents, documents protected by a password, and documents encrypted using public-key cryptography. ### Methods - **`PdfDocument::open(bytes: &[u8]) -> Result`** Opens an unencrypted PDF document or a document with an empty password. - **`PdfDocument::open_with_password(bytes: &[u8], password: &[u8]) -> Result`** Opens a PDF document that requires a user or owner password for decryption. - **`PdfDocument::open_with_certificate(pdf_bytes: &[u8], recipient_cert_der: &[u8], recipient_private_key_der: &[u8]) -> Result`** Opens a public-key encrypted PDF (Adobe.PubSec) by providing the recipient's DER-encoded X.509 certificate and DER-encoded RSA private key. ### Error Handling - `PdfError::InvalidPassword`: Surfaces when an incorrect password or an unrelated certificate is provided. This error can be handled using `Result::or_else` to prompt the user for a retry. - `PdfError::Unsupported`: Surfaces for unsupported encryption configurations. ``` -------------------------------- ### Serialize PDF File to Byte Sequence Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/04-object-model.md Produces a complete, valid PDF byte sequence from a PdfFile using a full-save rewrite. This is the only serialization path and ensures byte-for-byte identical output for identical input. ```rust pub fn serialize_pdf(file: &PdfFile) -> Vec ``` -------------------------------- ### Matrix Multiplication Order for 'cm' Operator Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/05-graphics-state.md Demonstrates the correct way to apply the 'cm' operator by pre-multiplying the new matrix onto the existing CTM. Incorrect post-multiplication can lead to significant coordinate transformation errors. ```rust ctm = matrix.multiply(ctm); // correct: pre-multiply // NOT: ctm = ctm.multiply(matrix); // wrong: post-multiply ``` -------------------------------- ### Open PDF with Password Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/reference/ts-sdk.md Opens an encrypted PDF using the supplied password. The password is tried first as the user password, then as the owner password; if neither authenticates, the call throws. The password is interpreted as UTF-8 bytes. For unencrypted documents the password is ignored. ```APIDOC ## openPdfWithPassword(input: Uint8Array, password: string): PdfHandle ### Description Opens an encrypted PDF using the supplied password. The password is tried first as the user password, then as the owner password; if neither authenticates, the call throws. The password is interpreted as UTF-8 bytes. For unencrypted documents the password is ignored. ### Method N/A (Function Call) ### Parameters #### Request Body - **input** (Uint8Array) - Required - The byte array representing the PDF file. - **password** (string) - Required - The password for the encrypted PDF. ### Response #### Success Response - **PdfHandle** - An opaque handle used for further operations on the PDF. #### Response Example ```json { "example": "PdfHandle" } ``` ``` -------------------------------- ### Point Transformation with Matrix Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Illustrates how a point [x y 1] is transformed by a matrix M using row-vector convention. ```text [x' y' 1] = [x y 1] * M x' = x*a + y*c + e y' = x*b + y*d + f ``` -------------------------------- ### Open PDF Document (TypeScript/Wasm) Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/encrypted-pdfs.md Initialize the WASM module using `initWasm`. Use `openPdf` for unencrypted documents, and `openPdfWithPassword` for password-protected ones. Handle potential 'invalid password' errors to prompt the user. ```typescript import { initWasm, openPdf, openPdfWithPassword, } from "@fabifont/open-redact-pdf"; await initWasm(); try { const handle = openPdf(bytes); /* ... */ } catch (caught) { if (caught instanceof Error && /invalid password/i.test(caught.message)) { const handle = openPdfWithPassword(bytes, await promptForPassword()); /* ... */ } else { throw caught; } } ``` -------------------------------- ### Glyph Position Computation Pipeline Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/internals/02-pdf-primer.md Shows the complete pipeline for computing a glyph's position from its local space to normalized page space. ```text local_rect (in text units) → .transform(text_matrix * CTM * page_transform) → quad in normalized page space ``` -------------------------------- ### Open Public-Key Encrypted PDF (Rust) Source: https://github.com/fabifont/open-redact-pdf/blob/main/docs/guides/encrypted-pdfs.md For public-key encrypted PDFs using Adobe.PubSec, provide the DER-encoded recipient certificate and private key to `PdfDocument::open_with_certificate`. ```rust // Public-key encrypted (Adobe.PubSec): supply DER-encoded cert and key. let document = PdfDocument::open_with_certificate( &pdf_bytes, &recipient_cert_der, &recipient_private_key_der, )? ```