Repository navigation
feat: ✨ add support for page lazy-loading #42
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
17 commits
Select commit
Hold shift + click to select a range
cc14f64
feat: :sparkles: add support for lazier-loading
sebO-S 187fb6b
address review
sebO-S e78bc24
address review + fix readme
sebO-S d42c892
update doc
sebO-S 3c4638d
fix typos
sebO-S 8bea751
address review
sebO-S 3d5730d
address review
sebO-S e40a542
address review again
sebO-S 9f66c55
address latest review
sebO-S 11265ef
address review again
sebO-S 184d9ed
address latest review
sebO-S e9ceb42
fixes
sebO-S a2eb983
fix review
sebO-S 94bed5b
fix latest issues
sebO-S c29aab7
dedupe handle check
sebO-S 9a9cdba
fix dead code doc
sebO-S 8597cd2
Update README.md
sebO-S File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| --- | ||
| sidebar_position: 4 | ||
| sidebar_position: 7 | ||
| --- | ||
|
|
||
| # drawLayer | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| --- | ||
| sidebar_position: 2 | ||
| sidebar_position: 5 | ||
| --- | ||
|
|
||
| # drawShape | ||
|
|
||
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,23 @@ | ||
| --- | ||
| sidebar_position: 1 | ||
| sidebar_position: 3 | ||
| --- | ||
|
|
||
| # getImageFromPDF | ||
| # getImagesFromPDF | ||
|
|
||
| - Type : `(file: string) => Promise` | ||
| :::caution Deprecated | ||
| `getImagesFromPDF` renders and holds **every** page in memory at once. Use [openPDF](/docs/Utils/open-pdf) or the [usePDFDocument](/docs/Utils/use-pdf-document) hook to render pages progressively instead. | ||
| ::: | ||
|
|
||
| > The parameter should be a valid Object URL of type string. If you have an object of type [File](https://developer.mozilla.org/fr/docs/Web/API/File) ( typically generated by file upload libraries) in hand you must use [URL.createObjectURL()](https://developer.mozilla.org/fr/docs/Web/API/URL/createObjectURL) to generate a valid URL object. | ||
| - Type : `(source: PDFSource, maxPages?: number, onSuccess?: () => void, resolution?: number) => Promise<string[]>` | ||
|
|
||
| > Renders every page of a PDF to a PNG data URL. Pages that fail to render are skipped, so the result may be shorter than the page count. `source` accepts a URL string, a `File`/`Blob`, an `ArrayBuffer` or a `Uint8Array`. | ||
|
|
||
| ```javascript | ||
| getImagesFromPDF(file).then((images) => { | ||
| // Do something with images pdf pages | ||
| // images: ['data:image/png;base64,...', ...] | ||
| }) | ||
| ``` | ||
|
|
||
| - **`maxPages`** : rejects with a `TooManyPagesError` when the document has more pages. | ||
| - **`onSuccess`** : called once the document has been accepted, before pages are rendered. | ||
| - **`resolution`** : target pixel count of each page, see [PDFPageOptions](/docs/Utils/open-pdf#page-options). |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,15 +1,20 @@ | ||
| --- | ||
| sidebar_position: 2 | ||
| sidebar_position: 4 | ||
| --- | ||
|
|
||
| # getPDFPageCount | ||
|
|
||
| - Type : `(file: string) => Promise<number>` | ||
| - Type : `(source: PDFSource) => Promise<number>` | ||
| - `PDFSource` : `string | Blob | ArrayBuffer | Uint8Array` | ||
|
|
||
| > The parameter should be a valid Object URL of type string. If you have an object of type [File](https://developer.mozilla.org/fr/docs/Web/API/File) ( typically generated by file upload libraries) in hand you must use [URL.createObjectURL()](https://developer.mozilla.org/fr/docs/Web/API/URL/createObjectURL) to generate a valid URL object. | ||
| > Returns the number of pages without rendering anything. | ||
|
|
||
| ```javascript | ||
| getPDFPageCount(file).then((pageCount) => { | ||
| // Do something with the page count | ||
| }) | ||
| ``` | ||
|
|
||
| :::tip | ||
| If you also need to render pages, call [openPDF](/docs/Utils/open-pdf) once and read `numPages` from the handle so the document is only parsed once. | ||
| ::: |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,102 @@ | ||
| --- | ||
| sidebar_position: 1 | ||
| --- | ||
|
|
||
| # openPDF | ||
|
|
||
| - Type : `(source: PDFSource, options?: OpenPDFOptions) => Promise<PDFDocumentHandle>` | ||
|
|
||
| > Parses a PDF once and returns a handle from which pages are rendered **on demand**. Only the pages you ask for are rasterized, the requested one first, and memory is released by `destroy()`. This is the primitive behind [usePDFDocument](/docs/Utils/use-pdf-document) and the recommended way to display documents with more than a handful of pages. | ||
|
|
||
| pdf.js and its Web Worker are downloaded lazily, the first time a PDF is processed, and a single worker is shared by every document in the tab. | ||
|
|
||
| ```ts | ||
| import { openPDF } from 'react-mindee-js' | ||
|
|
||
| const doc = await openPDF(file, { maxPages: 100 }) | ||
| doc.numPages // 5 | ||
|
|
||
| const first = await doc.getPage(1, { priority: 'high' }) // blob: URL | ||
| for await (const { pageNumber, image } of doc.getPages(2, 4)) { | ||
| // inclusive range, yielded as soon as each page is ready | ||
| } | ||
|
|
||
| await doc.destroy() // revokes every blob: URL handed out by this handle | ||
| ``` | ||
|
|
||
| ## Source | ||
|
|
||
| `PDFSource = string | Blob | ArrayBuffer | Uint8Array` | ||
|
|
||
| A URL or data URL string, a [File](https://developer.mozilla.org/docs/Web/API/File)/`Blob` (typically from a file input or upload library), or raw bytes. You no longer need `URL.createObjectURL()` to pass a `File`. | ||
|
|
||
| ## Options | ||
|
|
||
| ```ts | ||
| interface OpenPDFOptions { | ||
| /** Rejects with a `TooManyPagesError` when the document has more pages. */ | ||
| maxPages?: number | ||
| /** Aborting stops the download/parse and rejects with an `AbortError`. */ | ||
| signal?: AbortSignal | ||
| } | ||
| ``` | ||
|
|
||
| ## Handle | ||
|
|
||
| ```ts | ||
| interface PDFDocumentHandle { | ||
| readonly numPages: number | ||
| /** Renders a single page. `pageNumber` is 1-based, like pdf.js. */ | ||
| getPage: (pageNumber: number, options?: PDFPageOptions) => Promise<string> | ||
| /** Renders pages `from` to `to` inclusive (1-based) one after the other, yielding each as soon as it is ready. */ | ||
| getPages: (from: number, to: number, options?: PDFPageOptions) => AsyncIterable<PDFRenderedPage> | ||
| /** Cancels pending renders, revokes every object URL and releases the pdf.js document. */ | ||
| destroy: () => Promise<void> | ||
| } | ||
|
|
||
| interface PDFRenderedPage { | ||
| pageNumber: number // 1-based | ||
| image: string | ||
| } | ||
| ``` | ||
|
|
||
| :::caution | ||
| Page numbers are **1-based**. `getPage(0)`, a page above `numPages` or an inverted range reject with a `RangeError` before anything is rendered. | ||
| ::: | ||
|
|
||
| ## Page options | ||
|
|
||
| ```ts | ||
| interface PDFPageOptions { | ||
| resolution?: number // default 1 500 000 px (width × height), must be > 0 | ||
| output?: 'object-url' | 'data-url' // default 'object-url' | ||
| priority?: 'high' | 'low' // default 'high' for getPage, 'low' for getPages | ||
| signal?: AbortSignal | ||
| } | ||
| ``` | ||
|
|
||
| - **`resolution`** : target pixel count of the render. The viewer displays 1.5 Mpx; use a much lower value such as `50_000` for thumbnails. Renders at different resolutions are cached independently. | ||
| - **`output`** : `object-url` returns a `blob:` URL backed by a PNG blob, which is light to hold in memory and is revoked by `destroy()`. `data-url` returns a self-contained base64 PNG string. | ||
| - **`priority`** : `high` puts the request ahead of everything still waiting, so a page the user explicitly asked for is drawn before background prefetches. Requesting an already queued page again with `high` promotes it. | ||
| - **`signal`** : aborting removes the request from the queue (or cancels the in-progress render) and rejects **that caller's** promise with an `AbortError`. Other callers waiting on the same page are unaffected; the render itself is only cancelled once nobody waits for it. | ||
|
|
||
| ## Behaviour | ||
|
|
||
| - Pages render one at a time per document, in priority order. Every successful render is cached per page, resolution and output for the lifetime of the handle. | ||
| - Several calls for the same page share one render. | ||
| - `getPages` requests one page at a time, so breaking out of the `for await` loop leaves nothing pending. | ||
| - After `destroy()`, every pending call rejects (even a render that was about to complete) and the handle is unusable. | ||
|
|
||
| :::caution | ||
| Images are `blob:` object URLs by default: they only exist in the current tab and only until `destroy()`. To upload one, read it back first (`await fetch(url).then((r) => r.blob())`) or request `{ output: 'data-url' }`. | ||
| ::: | ||
|
|
||
| ## Errors | ||
|
|
||
| | `error.name` | Cause | | ||
| | :-------------------- | :------------------------------------------------------ | | ||
| | `InvalidPDFException` | The source is not a readable PDF | | ||
| | `TooManyPagesError` | The document has more pages than `maxPages` | | ||
| | `RangeError` | A page number or range is outside `1..numPages` | | ||
| | `AbortError` | The request's `signal` was aborted | | ||
| | `Error` | A render was requested after `destroy()` | |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,5 +1,5 @@ | ||
| --- | ||
| sidebar_position: 3 | ||
| sidebar_position: 6 | ||
| --- | ||
|
|
||
| # setShapeConfig | ||
|
|
||
Oops, something went wrong.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.