### Install LibPDF with Bun Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Use this command to install the core library with Bun. ```bash bun add @libpdf/core ``` -------------------------------- ### Start Development Server Source: https://github.com/libpdf-js/core/blob/main/apps/docs/README.md Run this command to start the development server. Open http://localhost:3000 to view the documentation. ```bash bun dev ``` -------------------------------- ### Install LibPDF with yarn Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Use this command to install the core library with yarn. ```bash yarn add @libpdf/core ``` -------------------------------- ### Clone and Install Dependencies with Bun Source: https://github.com/libpdf-js/core/blob/main/README.md Instructions for cloning the repository, installing dependencies using Bun, and running tests and type checks. ```bash # Clone the repo git clone https://github.com/libpdf/core.git cd libpdf # Install dependencies bun install # Run tests bun run test # Type check bun run typecheck ``` -------------------------------- ### Install Project Dependencies Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md Install project dependencies using the Bun package manager. ```bash bun install ``` -------------------------------- ### Progressive Code Examples Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Shows how to progressively introduce complexity in code examples, starting with basic usage and adding options and error handling. ```typescript // Basic usage const pdf = await PDF.load(bytes); // With options const pdf = await PDF.load(bytes, { credentials: "password", }); // Full example with error handling try { const pdf = await PDF.load(bytes, { credentials: "password", lenient: false, }); } catch (error) { if (error instanceof PasswordError) { // Handle wrong password } } ``` -------------------------------- ### Install LibPDF Core Source: https://github.com/libpdf-js/core/blob/main/README.md Install the LibPDF core library using npm or bun. ```bash npm install @libpdf/core # or bun add @libpdf/core ``` -------------------------------- ### Install OpenCode Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md Command to install OpenCode using a curl script. ```bash curl -fsSL https://opencode.ai/install | bash ``` -------------------------------- ### Install LibPDF with pnpm Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Use this command to install the core library with pnpm. ```bash pnpm add @libpdf/core ``` -------------------------------- ### Complete PDF Signing Example with Timestamp Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/index.mdx A comprehensive example demonstrating how to load a PDF, create a signer from a P12 certificate, configure a timestamp authority, sign the document with a timestamp, and save it using incremental updates. ```typescript import { readFile, writeFile } from "fs/promises"; import { PDF, P12Signer, HttpTimestampAuthority } from "@libpdf/core"; async function signDocument() { // Load document const pdfBytes = await readFile("contract.pdf"); const pdf = await PDF.load(pdfBytes); // Create signer const p12Bytes = await readFile("my-certificate.p12"); const signer = await P12Signer.create(p12Bytes, "p12-password"); // Create timestamp authority const tsa = new HttpTimestampAuthority("http://timestamp.digicert.com"); // Sign with timestamp const signed = await pdf.sign({ signer, level: "B-LT", timestampAuthority: tsa, reason: "Contract approval", location: "San Francisco, CA", fieldName: "ApprovalSignature", }); // Save with incremental update await writeFile("contract-signed.pdf", signed.bytes); console.log("Document signed successfully"); } signDocument().catch(console.error); ``` -------------------------------- ### Verify Installation Script Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Create and run this script to confirm that LibPDF is installed correctly and can create a basic PDF. ```typescript import { PDF } from "@libpdf/core"; const pdf = PDF.create(); pdf.addPage(); const bytes = await pdf.save(); console.log(`Created PDF with ${bytes.length} bytes`); ``` -------------------------------- ### Install LibPDF with npm Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Use this command to install the core library with npm. ```bash npm install @libpdf/core ``` -------------------------------- ### Complete PDF Generation Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/create-pdf.mdx A comprehensive example demonstrating the creation of an invoice PDF, including setting metadata, adding a page, drawing text and lines, and saving the file. Requires Node.js `fs/promises`. ```typescript import { readFile, writeFile } from "fs/promises"; import { PDF, rgb } from "@libpdf/core"; // Create document const pdf = PDF.create(); pdf.setTitle("Invoice #1234"); // Add page const page = pdf.addPage({ size: "a4" }); // Header page.drawText("INVOICE", { x: 50, y: 780, size: 32, color: rgb(0.2, 0.2, 0.2), }); page.drawText("Invoice #1234", { x: 50, y: 740, size: 14, }); // Line separator page.drawLine({ start: { x: 50, y: 720 }, end: { x: 545, y: 720 }, color: rgb(0.8, 0.8, 0.8), thickness: 1, }); // Content page.drawText("Description: Professional Services", { x: 50, y: 680, size: 12, }); page.drawText("Amount: $1,500.00", { x: 50, y: 660, size: 12, }); // Save const bytes = await pdf.save(); await writeFile("invoice.pdf", bytes); console.log("Created invoice.pdf"); ``` -------------------------------- ### Browser Usage Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx This example demonstrates how to load a PDF document in the browser using fetch and Uint8Array. No Node.js polyfills are required. ```typescript // Works the same in browsers import { PDF } from "@libpdf/core"; const response = await fetch("/document.pdf"); const bytes = new Uint8Array(await response.arrayBuffer()); const pdf = await PDF.load(bytes); ``` -------------------------------- ### Complete Example: Gradient Button Source: https://github.com/libpdf-js/core/blob/main/content/docs/advanced/low-level-drawing.mdx A full example demonstrating the creation of a PDF document with a gradient button. It includes setting up gradients, patterns, transparency for shadows, and drawing text. ```typescript import { PDF, ops, rgb, Matrix, ColorSpace } from "@libpdf/core"; const pdf = PDF.create(); const page = pdf.addPage(); // Create button gradient const gradient = pdf.createLinearGradient({ angle: 180, // top to bottom length: 40, stops: [ { offset: 0, color: rgb(0.4, 0.6, 1) }, { offset: 1, color: rgb(0.2, 0.4, 0.8) }, ], }); const pattern = pdf.createShadingPattern({ shading: gradient }); const patternName = page.registerPattern(pattern); // Create shadow with transparency const shadow = pdf.createExtGState({ fillOpacity: 0.3 }); const shadowName = page.registerExtGState(shadow); // Draw shadow page.drawOperators([ ops.pushGraphicsState(), ops.setGraphicsState(shadowName), ops.setNonStrokingGray(0), ops.rectangle(103, 697, 150, 40), ops.fill(), ops.popGraphicsState(), ]); // Draw button with gradient page.drawOperators([ ops.setNonStrokingColorSpace(ColorSpace.Pattern), ops.setNonStrokingColorN(patternName), ]); // Rounded rectangle path page .drawPath() .moveTo(110, 700) .lineTo(250, 700) .curveTo(255, 700, 260, 705, 260, 710) .lineTo(260, 730) .curveTo(260, 735, 255, 740, 250, 740) .lineTo(110, 740) .curveTo(105, 740, 100, 735, 100, 730) .lineTo(100, 710) .curveTo(100, 705, 105, 700, 110, 700) .close() .fill({ pattern }); // Add button text page.drawText("Click Me", { x: 145, y: 714, size: 14, color: rgb(1, 1, 1), }); await Bun.write("button.pdf", await pdf.save()); ``` -------------------------------- ### File Structure Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Illustrates the directory structure for organizing documentation files within the content/docs/ directory. ```tree content/docs/ ├── index.mdx # Landing page with feature matrix ├── getting-started/ # Installation and first steps ├── guides/ # Task-based how-to guides ├── api/ # Class and method reference ├── concepts/ # PDF internals explanations ├── advanced/ # Power user topics └── migration/ # Migration guides ``` -------------------------------- ### Install Google Cloud Secret Manager Client Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Install the client for loading certificates from Google Cloud Secret Manager. This is needed if your certificates are stored there. ```bash npm install @google-cloud/secret-manager ``` -------------------------------- ### Complete PDF Drawing Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/drawing.mdx This example demonstrates how to create a PDF document, add a page, and draw various elements like background, header, title, section headers, lines, and text with different colors and sizes. It concludes by saving the PDF to a file. ```typescript import { writeFile } from "fs/promises"; import { PDF, rgb } from "@libpdf/core"; const pdf = PDF.create(); const page = pdf.addPage({ size: "a4" }); const { width, height } = page; // Background page.drawRectangle({ x: 0, y: 0, width, height, color: rgb(0.98, 0.98, 1), }); // Header bar page.drawRectangle({ x: 0, y: height - 60, width, height: 60, color: rgb(0.2, 0.4, 0.8), }); page.drawText("Document Title", { x: 50, y: height - 40, size: 24, color: rgb(1, 1, 1), }); // Content page.drawText("Section 1", { x: 50, y: height - 120, size: 18, color: rgb(0.2, 0.2, 0.2), }); page.drawLine({ start: { x: 50, y: height - 130 }, end: { x: width - 50, y: height - 130 }, color: rgb(0.8, 0.8, 0.8), thickness: 1, }); page.drawText("Lorem ipsum dolor sit amet, consectetur adipiscing elit.", { x: 50, y: height - 160, size: 12, maxWidth: width - 100, lineHeight: 18, }); await writeFile("styled-document.pdf", await pdf.save()); ``` -------------------------------- ### Install Google Cloud KMS Client Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Install the optional peer dependency for the Google Cloud KMS client. This is required for signing PDFs with KMS. ```bash npm install @google-cloud/kms ``` -------------------------------- ### Parameter Table Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Illustrates the format for documenting method parameters using a Markdown table, including nested options and default values. ```markdown ### methodName(param, options?) Description of what the method does. | Param | Type | Default | Description | | ------------------- | --------- | -------- | --------------------- | | `param` | `string` | required | What it does | | `[options]` | `Options` | | | | `[options.setting]` | `boolean` | `false` | Nested option | | `[options.timeout]` | `number` | `5000` | Another nested option | **Returns**: `Promise` **Throws**: - `SpecificError` - When something goes wrong ``` -------------------------------- ### Common Development Commands Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md A list of common commands for running tests, type checking, linting, building, and running examples. ```bash bun run test # Run tests in watch mode ``` ```bash bun run test:run # Run tests once ``` ```bash bun run typecheck # Type check with tsc ``` ```bash bun run lint # Check with oxlint + oxfmt ``` ```bash bun run lint:fix # Fix lint issues ``` ```bash bun run build # Build for distribution ``` ```bash bun run examples # Run all examples ``` -------------------------------- ### Table Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Provides an example of using Markdown tables for feature matrices, parameter documentation, comparison charts, or error catalogs. ```markdown | Feature | Status | Notes | | ----------- | ------ | -------------- | | PDF 1.0-1.7 | Full | Read and write | | PDF 2.0 | Read | Write planned | ``` -------------------------------- ### PDF Object Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/pdf-structure.mdx An example of a PDF object, which contains document content. Object 1 is a dictionary referencing object 2. ```text 1 0 obj << /Type /Catalog /Pages 2 0 R >> endobj ``` -------------------------------- ### Branch Naming Conventions Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md Examples of branch naming conventions for different types of contributions. ```bash feat/short-description # New features ``` ```bash fix/short-description # Bug fixes ``` ```bash docs/short-description # Documentation changes ``` ```bash refactor/short-description # Code refactoring ``` -------------------------------- ### Callout Examples Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Demonstrates the usage of Fumadocs callouts for highlighting informational, warning, and critical messages within documentation. ```mdx Informational note about behavior. Warning about potential issues or breaking changes. Critical warning about data loss or security. ``` -------------------------------- ### MDX Page Structure Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Demonstrates the basic structure of an MDX documentation page, including frontmatter, headings, and sections. ```mdx --- title: Feature Name description: Brief description for SEO and previews. --- # Feature Name Brief description of what this does and when to use it. ## Quick Start ```typescript // Minimal working example ``` --- ## Section Name Content organized by task or concept. --- ## See Also - [Related Guide](/docs/guides/related) ``` -------------------------------- ### Full Rewrite Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/incremental-saves.mdx Illustrates the structure of a full rewrite save operation, which rebuilds the entire PDF. ```text [New PDF with all objects reorganized] %%EOF ``` -------------------------------- ### Meta JSON Configuration Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Example of a meta.json file used to control navigation order and titles within a documentation directory. ```json { "title": "Section Title", "pages": ["index", "page-one", "page-two"] } ``` -------------------------------- ### PDF Cross-Reference Table Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/pdf-structure.mdx The xref table maps object numbers to their byte offsets within the file. This example shows entries for objects 0 through 4. ```text xref 0 5 0000000000 65535 f 0000000009 00000 n 0000000058 00000 n 0000000115 00000 n 0000000267 00000 n ``` -------------------------------- ### Load Test Fixture Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md Example of loading a test fixture using a helper function in TypeScript. ```typescript import { loadFixture } from "./test-utils.ts"; const bytes = await loadFixture("basic", "hello.pdf"); ``` -------------------------------- ### Loading Test Fixtures Source: https://github.com/libpdf-js/core/blob/main/CLAUDE.md Use the typed helper function to load fixtures for testing. This example demonstrates loading a PDF file. ```typescript import { loadFixture } from "./test-utils.ts"; const bytes = await loadFixture("basic", "rot0.pdf"); ``` -------------------------------- ### MDX Frontmatter Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Shows the required frontmatter for MDX pages, including title and description for SEO and previews. ```yaml --- title: Working with Pages description: Add, remove, reorder, copy, and merge PDF pages. --- ``` -------------------------------- ### Error Documentation Example Source: https://github.com/libpdf-js/core/blob/main/WRITING_STYLE.md Shows how to document errors by categorizing them and providing common causes and solutions for specific error types. ```markdown ## Parse Errors Thrown when loading a PDF. ### InvalidHeaderError PDF header is missing or malformed. **Common causes:** - File is not a PDF - File truncated during transfer **Solution:** Verify the file is a valid PDF. ``` -------------------------------- ### PDF Header Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/pdf-structure.mdx The first line of a PDF file declares its version. ```text %PDF-1.7 ``` -------------------------------- ### PDF Trailer Example Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/pdf-structure.mdx The trailer provides essential information for locating the document's root object and the cross-reference table. ```text trailer << /Root 1 0 R /Size 5 >> startxref 1234 %%EOF ``` -------------------------------- ### Quick Start: Sign PDF with Google KMS Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Load a certificate, create a GoogleKmsSigner with your key version name, and sign a PDF document. The signed PDF is then saved to a file. ```typescript import { PDF, GoogleKmsSigner } from "@libpdf/core"; import { readFile, writeFile } from "fs/promises"; // Load your DER-encoded certificate (issued by your CA for the KMS key) const certificate = await readFile("certificate.der"); // Create signer with KMS key reference const signer = await GoogleKmsSigner.create({ keyVersionName: "projects/my-project/locations/us-east1/keyRings/my-ring/cryptoKeys/my-key/cryptoKeyVersions/1", certificate, }); // Sign the PDF const pdf = await PDF.load(await readFile("document.pdf")); const { bytes } = await pdf.sign({ signer }); await writeFile("signed.pdf", bytes); ``` -------------------------------- ### Usage-focused PDF API Example (TypeScript) Source: https://github.com/libpdf-js/core/blob/main/AGENTS.md Demonstrates how users will interact with the PDF embedding and field setting API. Focuses on the desired outcome from an external perspective. ```typescript // GOOD: Shows desired API from user's perspective const font = await pdf.embedFont(fontBytes); field.setFont(font); field.setValue("Hello 世界"); ``` -------------------------------- ### Create an Empty PDF Document Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/create-pdf.mdx Initializes a new PDF document object. This is the starting point for all PDF generation tasks. ```typescript import { PDF } from "@libpdf/core"; const pdf = PDF.create(); ``` -------------------------------- ### Internal Implementation Example (TypeScript) Source: https://github.com/libpdf-js/core/blob/main/AGENTS.md Illustrates an internal, prescriptive class implementation that should be avoided in planning. This level of detail is discovered during coding. ```typescript // BAD: Prescribes internal implementation export class TTFParser { private parseTables(data: Uint8Array): Map { const view = new DataView(data.buffer, data.byteOffset); const numTables = view.getUint16(4); // ... 50 more lines of implementation } } ``` -------------------------------- ### Get Pages from PDF Source: https://github.com/libpdf-js/core/blob/main/content/docs/migration/from-pdf-lib.mdx Illustrates retrieving all pages, a specific page by index, and the total page count. ```typescript // pdf-lib const pages = pdfDoc.getPages(); const page = pdfDoc.getPage(0); const count = pdfDoc.getPageCount(); // LibPDF const pages = pdf.getPages(); const page = pdf.getPage(0); const count = pdf.getPageCount(); ``` -------------------------------- ### Build Documentation Source: https://github.com/libpdf-js/core/blob/main/apps/docs/README.md Execute this command to build the documentation for deployment. ```bash bun run build ``` -------------------------------- ### Create and Use PdfNumber Objects Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/object-model.mdx Provides examples of creating PDF numbers, distinguishing between integers and real numbers, and accessing their numerical values. ```typescript import { PdfNumber } from "@libpdf/core"; const int = PdfNumber.of(42); const real = PdfNumber.of(3.14159); int.value; // 42 real.value; // 3.14159 ``` -------------------------------- ### Drawing with Pattern Fills Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/drawing.mdx This example shows how to create and use pattern fills for shapes in libpdf.js. It includes creating a linear gradient and applying it to a rectangle and a path. ```typescript // Create a gradient pattern const gradient = pdf.createLinearGradient({ angle: 90, length: 100, stops: [ { offset: 0, color: rgb(1, 0, 0) }, { offset: 1, color: rgb(0, 0, 1) }, ], }); const pattern = pdf.createShadingPattern({ shading: gradient }); // Use with drawRectangle, drawCircle, drawEllipse, or drawPath page.drawRectangle({ x: 50, y: 500, width: 200, height: 100, pattern, }); // Also works with PathBuilder page.drawPath().circle(300, 550, 50).fill({ pattern }); ``` -------------------------------- ### Initialize Git Submodules Source: https://github.com/libpdf-js/core/blob/main/checkouts/README.md Run this command after cloning the repository to initialize and check out submodules. ```bash git submodule update --init --recursive ``` -------------------------------- ### GoogleKmsSigner Creation with Shorthand Options Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Create a GoogleKmsSigner instance using shorthand properties for project, location, key ring, and key IDs. This method is convenient for quick setup. ```APIDOC ## Create GoogleKmsSigner with Shorthand Options ### Description Instantiate a `GoogleKmsSigner` using shorthand parameters instead of full resource names. ### Method `GoogleKmsSigner.create(options)` ### Parameters #### Options Object - **options.projectId** (string) - Required - GCP project ID. - **options.locationId** (string) - Required - KMS location. - **options.keyRingId** (string) - Required - Key ring name. - **options.keyId** (string) - Required - Key name. - **options.keyVersion** (string) - Optional - Key version number. Defaults to "1". - **options.certificate** (Buffer) - Required - DER-encoded certificate. ### Request Example ```typescript const signer = await GoogleKmsSigner.create({ projectId: "my-project", locationId: "us-east1", keyRingId: "my-ring", keyId: "my-key", keyVersion: "1", certificate: certificateDer, }); ``` ### Response #### Success Response - **Promise** - A promise that resolves to the created `GoogleKmsSigner` instance. #### Throws - **KmsSignerError** - If the key is not found, not accessible, not enabled, or has an unsupported algorithm, or if the certificate's public key does not match the KMS key. ``` -------------------------------- ### Get All Field Names Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-form.mdx Returns an array of strings, where each string is the name of a form field. This is useful for quickly getting a list of available fields. ```typescript const names = form.getFieldNames(); // ["name", "email", "phone", "agree"] ``` -------------------------------- ### Set and Get Text Field Value Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-form.mdx Accesses a text field by name and allows setting or getting its value. Ensure the field is of type 'text' before using these methods. ```typescript const nameField = form.getTextField("name"); if (nameField) { nameField.setValue("John Doe"); console.log(nameField.getValue()); } ``` -------------------------------- ### Complete PDF Signing Example with Google KMS Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Demonstrates a full workflow for signing a PDF document using Google KMS. It includes loading a certificate from Secret Manager, creating a KMS signer with automatic chain building, loading the PDF, setting up a timestamp authority, and writing the signed PDF. ```typescript import { readFile, writeFile } from "fs/promises"; import { PDF, GoogleKmsSigner, HttpTimestampAuthority } from "@libpdf/core"; async function signWithKms() { // Load certificate from Secret Manager const certificate = await GoogleKmsSigner.getCertificateFromSecretManager( "projects/my-project/secrets/signing-cert/versions/latest", ); // Create KMS signer with automatic chain building const signer = await GoogleKmsSigner.create({ projectId: "my-project", locationId: "us-east1", keyRingId: "document-signing", keyId: "contract-key", certificate, buildChain: true, }); // Load document const pdf = await PDF.load(await readFile("contract.pdf")); // Create timestamp authority for long-term validation const tsa = new HttpTimestampAuthority("http://timestamp.digicert.com"); // Sign with timestamp const { bytes } = await pdf.sign({ signer, level: "B-LT", timestampAuthority: tsa, reason: "Contract approval", location: "Cloud signing service", }); await writeFile("contract-signed.pdf", bytes); console.log("Document signed with KMS"); } signWithKms().catch(console.error); ``` -------------------------------- ### Get All Pages Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/pages.mdx Retrieve all pages from a PDF document and log the total count. ```typescript const pages = pdf.getPages(); console.log(`Document has ${pages.length} pages`); ``` -------------------------------- ### Get All Pages Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf.mdx Retrieve an array containing all pages of the PDF document in their document order. ```typescript const pages = pdf.getPages(); for (const page of pages) { console.log(`Page ${page.index}: ${page.width} x ${page.height}`); } ``` -------------------------------- ### Create PDF with Feature and Save Output Source: https://github.com/libpdf-js/core/blob/main/src/integration/README.md An example of creating a new PDF document, adding a page, performing test operations, and saving the resulting PDF bytes to a file for visual inspection. Ensure to import necessary modules like PDF and saveTestOutput. ```typescript import { PDF } from "#src/api/pdf"; import { saveTestOutput } from "#src/test-utils"; describe("Feature Integration", () => { it("creates PDF with feature", () => { const pdf = PDF.create(); const page = pdf.addPage(); // ... test code ... const bytes = pdf.save(); saveTestOutput("feature/result.pdf", bytes); }); }); ``` -------------------------------- ### Get Page Properties Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/pages.mdx Access properties of a specific page, such as its dimensions, rotation, and index. ```typescript const page = pdf.getPage(0); // Dimensions in points (1 inch = 72 points) const { width, height } = page; // Rotation (0, 90, 180, or 270) const rotation = page.rotation; // Page index console.log(`Page ${page.index + 1} of ${pdf.getPageCount()}`); ``` -------------------------------- ### Get Page Count Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/parse-pdf.mdx Retrieve the total number of pages in the loaded PDF document. ```typescript console.log(pdf.getPageCount()); // e.g., 5 ``` -------------------------------- ### Usage-Focused API Example in Plans Source: https://github.com/libpdf-js/core/blob/main/CLAUDE.md When including code samples in plans, focus on the user's perspective and desired API interactions. Avoid prescribing internal implementation details. ```typescript // GOOD: Shows desired API from user's perspective const font = await pdf.embedFont(fontBytes); field.setFont(font); field.setValue("Hello 世界"); ``` ```typescript // BAD: Prescribes internal implementation export class TTFParser { private parseTables(data: Uint8Array): Map { const view = new DataView(data.buffer, data.byteOffset); const numTables = view.getUint16(4); // ... 50 more lines of implementation } } ``` -------------------------------- ### PDF Document Tree Structure Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/pdf-structure.mdx Illustrates the hierarchical relationship between PDF objects, starting from the Catalog. ```text Catalog (/Root) ├── Pages (page tree root) │ ├── Page 1 │ │ ├── Contents (drawing commands) │ │ └── Resources │ │ ├── Fonts │ │ └── Images │ ├── Page 2 │ └── ... ├── AcroForm (interactive forms) ├── Outlines (bookmarks) └── Metadata ``` -------------------------------- ### Get Single Page Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/pages.mdx Retrieve a specific page from a PDF document using its zero-based index. ```typescript const firstPage = pdf.getPage(0); const lastPage = pdf.getPage(pdf.getPageCount() - 1); ``` -------------------------------- ### Load, Inspect, and Fill PDF Form Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/forms.mdx This example demonstrates loading a PDF, accessing its form, listing fields, filling them with data, and saving the modified PDF. It also shows how to flatten the form to make fields non-editable. ```typescript import { readFile, writeFile } from "fs/promises"; import { PDF } from "@libpdf/core"; // Load form PDF const bytes = await readFile("application-form.pdf"); const pdf = await PDF.load(bytes); const form = pdf.getForm(); if (!form) { console.log("No form found"); return; } // Check what fields exist console.log("Form fields:"); for (const field of form.getFields()) { console.log(` ${field.name} (${field.type})`); } // Fill the form form.fill({ applicant_name: "Jane Smith", applicant_email: "jane@example.com", application_date: new Date().toISOString().split("T")[0], agree_terms: true, preferred_contact: "Email", }); // Save filled form await writeFile("filled-form.pdf", await pdf.save()); // Or flatten and save form.flatten(); await writeFile("flattened-form.pdf", await pdf.save()); ``` -------------------------------- ### Get Page Dimensions Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/parse-pdf.mdx Access a specific page from the PDF and retrieve its width and height in points. ```typescript const page = pdf.getPage(0); // Zero-indexed const { width, height } = page; console.log(`${width} x ${height} points`); // e.g., "612 x 792 points" for US Letter ``` -------------------------------- ### GoogleKmsSigner Creation with Key Version Name Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Create a GoogleKmsSigner instance by providing the full key version resource name and the certificate. ```APIDOC ## Create GoogleKmsSigner with Key Version Name ### Description Instantiate a `GoogleKmsSigner` using the full KMS key version resource name and the certificate. ### Method `GoogleKmsSigner.create(options)` ### Parameters #### Options Object - **options.keyVersionName** (string) - Required - Full resource name of the KMS key version (e.g., `projects/.../cryptoKeyVersions/1`). - **options.certificate** (Buffer) - Required - DER-encoded certificate. ### Request Example ```typescript const signer = await GoogleKmsSigner.create({ keyVersionName: "projects/.../cryptoKeyVersions/1", certificate: certificateDer, }); ``` ### Response #### Success Response - **Promise** - A promise that resolves to the created `GoogleKmsSigner` instance. ``` -------------------------------- ### Get All Checkboxes Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-form.mdx Returns an array of all checkbox fields in the form. This can be used to iterate through and manage multiple checkboxes. ```typescript form.getCheckboxes() ``` -------------------------------- ### Create GoogleKmsSigner with Shorthand Options Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Use shorthand properties for project, location, key ring, and key IDs when creating the signer. Ensure the certificate is DER-encoded. ```typescript const signer = await GoogleKmsSigner.create({ projectId: "my-project", locationId: "us-east1", keyRingId: "my-ring", keyId: "my-key", keyVersion: "1", certificate: certificateDer, }); ``` -------------------------------- ### Iterate Over All Pages Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/parse-pdf.mdx Get a collection of all pages in the PDF and iterate through them, extracting and logging a preview of the text from each page. ```typescript const pages = pdf.getPages(); for (const page of pages) { const pageText = page.extractText(); console.log(`Page ${page.index + 1}: ${pageText.text.slice(0, 100)}...`); } ``` -------------------------------- ### Create New PDF Document Source: https://github.com/libpdf-js/core/blob/main/content/docs/migration/from-pdf-lib.mdx Shows how to create a new PDF document synchronously with LibPDF and asynchronously with pdf-lib. ```typescript // pdf-lib import { PDFDocument } from "pdf-lib"; const pdfDoc = await PDFDocument.create(); // LibPDF import { PDF } from "@libpdf/core"; const pdf = PDF.create(); // Note: synchronous ``` -------------------------------- ### Run Specific Tests Source: https://github.com/libpdf-js/core/blob/main/CONTRIBUTING.md Command to run specific tests using a filter, for example, tests related to the 'parser'. ```bash bun run test:run -t "parser" ``` -------------------------------- ### Handle PDF Authentication and Permissions Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/encryption.mdx This example shows how to load an encrypted PDF, check authentication status, attempt authentication with a password, and handle specific permission errors when trying to modify protected documents. It requires the PDF object and `PermissionDeniedError`. ```typescript import { PDF, PermissionDeniedError } from "@libpdf/core"; // Load and check authentication status const pdf = await PDF.load(bytes, { credentials: "password" }); if (pdf.isEncrypted && !pdf.isAuthenticated) { console.log("Password required or incorrect"); } // Try to authenticate with a different password const result = pdf.authenticate("another-password"); if (result.authenticated) { console.log("Successfully authenticated"); console.log("Has owner access:", result.isOwner); } // Handle permission errors when modifying protected documents try { pdf.removeProtection(); } catch (error) { if (error instanceof PermissionDeniedError) { console.log("Requires owner access to remove protection"); } } ``` -------------------------------- ### Get Page Height Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-page.mdx Accesses the height of the PDF page in points. This value accounts for any rotation applied to the page. ```typescript const height = page.height; // e.g., 792 for US Letter ``` -------------------------------- ### Get Page Width Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-page.mdx Accesses the width of the PDF page in points. This value accounts for any rotation applied to the page. ```typescript const width = page.width; // e.g., 612 for US Letter ``` -------------------------------- ### Get a Specific Page Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf.mdx Retrieve a single page from the document by its 0-based index. Returns null if the index is out of bounds. ```typescript const page = pdf.getPage(0); if (page) { console.log(`Size: ${page.width} x ${page.height}`); } ``` -------------------------------- ### Create Invoice with @libpdf/core Source: https://github.com/libpdf-js/core/blob/main/content/docs/migration/from-pdf-lib.mdx Example of creating an invoice PDF using the @libpdf/core library. This demonstrates the equivalent functionality with the updated API, including creating a PDF, adding pages, and drawing text. ```typescript import { PDF, rgb, } from "@libpdf/core"; async function createInvoice(data: InvoiceData) { const pdf = PDF.create(); const page = pdf.addPage({ size: "letter" }); page.drawText("INVOICE", { x: 50, y: 750, size: 24, font: "Helvetica", color: rgb(0, 0, 0), }); page.drawText(data.customerName, { x: 50, y: 700, size: 12, font: "Helvetica", }); return pdf.save(); } ``` -------------------------------- ### Get All Dropdowns Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf-form.mdx Returns an array of all dropdown (combo box) fields. This is useful for processing multiple dropdowns simultaneously. ```typescript form.getDropdowns() ``` -------------------------------- ### Create and Manipulate PdfDict Objects Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/object-model.mdx Demonstrates creating a PDF dictionary, accessing its values using typed getters, checking for key existence, setting new values, deleting keys, and iterating over its entries. ```typescript import { PdfArray, PdfDict, PdfName, PdfNumber, PdfString } from "@libpdf/core"; // Create a dictionary const dict = PdfDict.of({ Type: PdfName.of("Page"), MediaBox: new PdfArray([PdfNumber.of(0), PdfNumber.of(0), PdfNumber.of(612), PdfNumber.of(792)]), }); // Read values with typed getters const type = dict.getName("Type"); // PdfName | undefined const box = dict.getArray("MediaBox"); // PdfArray | undefined const count = dict.getNumber("Count"); // PdfNumber | undefined const title = dict.getString("Title"); // PdfString | undefined const ref = dict.getRef("Pages"); // PdfRef | undefined // Generic get (returns PdfObject | undefined) const value = dict.get("SomeKey"); // Check existence if (dict.has("Resources")) { // ... } // Set values dict.set("NewKey", PdfString.fromString("value")); // Delete keys dict.delete("OldKey"); // Iterate for (const [name, value] of dict) { console.log(`${name.value}: ${value.type}`); } ``` -------------------------------- ### Get Page Rotation Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/parse-pdf.mdx Retrieve the rotation angle of a specific page, which can be 0, 90, 180, or 270 degrees. ```typescript const rotation = page.rotation; // 0, 90, 180, or 270 ``` -------------------------------- ### Load PDF from File (Node.js/Bun) Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/parse-pdf.mdx Load a PDF from a file path in Node.js or Bun environments using fs/promises.readFile. ```typescript import { readFile } from "fs/promises"; import { PDF } from "@libpdf/core"; const bytes = await readFile("document.pdf"); const pdf = await PDF.load(bytes); ``` -------------------------------- ### Run All Integration Tests Source: https://github.com/libpdf-js/core/blob/main/src/integration/README.md Execute all integration tests within the src/integration directory. This command is useful for a comprehensive check of the library's end-to-end functionality. ```bash bun test src/integration ``` -------------------------------- ### Create and Use PdfString Objects Source: https://github.com/libpdf-js/core/blob/main/content/docs/concepts/object-model.mdx Demonstrates creating PDF strings from JavaScript strings (which are auto-encoded) and from raw byte arrays. Also shows how to retrieve the string representation and raw bytes. ```typescript import { PdfString } from "@libpdf/core"; // From a JavaScript string (auto-encodes) const str = PdfString.fromString("Hello, World!"); // From raw bytes const bytes = new Uint8Array([0x48, 0x65, 0x6c, 0x6c, 0x6f]); const str2 = PdfString.fromBytes(bytes); // Get as JavaScript string str.asString(); // "Hello, World!" // Get raw bytes str.bytes; // Uint8Array ``` -------------------------------- ### Sign a PDF Document Source: https://github.com/libpdf-js/core/blob/main/README.md Load a PDF, create a P12Signer with certificate and password, and sign the document with a reason. ```typescript import { PDF, P12Signer } from "@libpdf/core"; const pdf = await PDF.load(bytes); const signer = await P12Signer.create(p12Bytes, "password"); const signed = await pdf.sign({ signer, reason: "I approve this document", }); ``` -------------------------------- ### Run Verification Script Source: https://github.com/libpdf-js/core/blob/main/content/docs/getting-started/installation.mdx Execute the verification script using either npx with tsx or directly with Bun. ```bash npx tsx verify.ts # or with Bun bun run verify.ts ``` -------------------------------- ### Extract Text from a Single Page Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/text-extraction.mdx Get all text from a specific page as a single string. The text is extracted in reading order. ```typescript const page = pdf.getPage(0); const { text } = page.extractText(); console.log(text); ``` -------------------------------- ### Create GoogleKmsSigner with Key Version Name Source: https://github.com/libpdf-js/core/blob/main/content/docs/guides/signatures/google-kms.mdx Create a signer using the full KMS key version resource name. Inspect signer properties like key type, signature algorithm, and digest algorithm after creation. ```typescript const signer = await GoogleKmsSigner.create({ keyVersionName: "projects/.../cryptoKeyVersions/1", certificate: certificateDer, }); signer.keyType; // "RSA" or "EC" signer.signatureAlgorithm; // "RSASSA-PKCS1-v1_5", "RSA-PSS", or "ECDSA" signer.digestAlgorithm; // "SHA-256", "SHA-384", or "SHA-512" signer.keyVersionName; // Full resource name signer.certificate; // DER-encoded certificate signer.certificateChain; // Chain certificates (if provided/built) ``` -------------------------------- ### Run Tests Once with Bun Source: https://github.com/libpdf-js/core/blob/main/CLAUDE.md Use this command to run all project tests a single time. Suitable for CI environments or a quick check. ```bash bun run test:run ``` -------------------------------- ### Project Structure Overview Source: https://github.com/libpdf-js/core/blob/main/AGENTS.md Illustrates the directory layout for the @libpdf/core project, including source code, fixtures, reference libraries, and agent working documents. ```plaintext src/ index.ts # Main entry point test-utils.ts # Shared test utilities (loadFixture, byte helpers) fixtures/ # PDF test files organized by feature basic/ # Simple PDFs for core parsing xref/ # XRef table/stream tests filter/ # Stream compression tests encryption/ # Encrypted PDF tests malformed/ # Error recovery tests text/ # Text extraction tests checkouts/ # Reference library submodules (read-only) pdfjs/ # Mozilla pdf.js - parsing reference pdf-lib/ # pdf-lib - generation API reference pdfbox/ # Apache PDFBox - architecture reference .agents/ # AI agent working documents (see below) .docs/ # Local documentation (not committed, see below) ``` -------------------------------- ### Get PDF Security Information Source: https://github.com/libpdf-js/core/blob/main/content/docs/api/pdf.mdx Retrieves detailed security information about the PDF document, including encryption status, algorithm, and permissions. ```typescript const security = pdf.getSecurity(); console.log(`Encrypted: ${security.isEncrypted}`); console.log(`Algorithm: ${security.algorithm}`); console.log(`Can copy: ${security.permissions.copy}`); ``` -------------------------------- ### Create New PDF with PDF.create Source: https://context7.com/libpdf-js/core/llms.txt Creates a blank PDF document. Use `addPage` to add pages with preset or custom sizes. Pages can be inserted at a specific position. ```typescript import { PDF } from "@libpdf/core"; const pdf = PDF.create(); // Add pages with preset sizes const letterPage = pdf.addPage({ size: "letter" }); // 612 x 792 pt const a4Page = pdf.addPage({ size: "a4" }); // 595 x 842 pt const customPage = pdf.addPage({ width: 400, height: 600 }); // custom points // Insert at specific position const coverPage = pdf.addPage({ size: "letter", insertAt: 0 }); console.log(`Pages: ${pdf.getPageCount()}`); // 4 const bytes = await pdf.save(); ```