Split, reorder and repack, on the device.
Explode any PDF, multi-page TIFF or image file into per-page images, let people pull out single pages, drag them into a new order, drop the ones they don't want, then rebuild a fresh PDF or TIFF. Every step runs in the browser. Nothing is uploaded.
Four steps, no round-trip
A page organizer is the same four moves every time. The SDK covers the first and the last; the middle two are plain array work in your own code.
Read the file into a Uint8Array. Call readImageInformation for page count and per-page size, colour type and DPI.
compressToJPG fans a PDF, TIFF or image file out into one JPEG per page, an ordinary array you can render as thumbnails.
Your UI reorders or filters the array. No SDK call, the pages are already just bytes sitting in memory.
Hand the surviving pages, in their new order, to compressToPdf or compressToTiff to rebuild one document.
Extract, rearrange, repack
Explode a document into pages
Pass a multi-page PDF or TIFF, or JPEG, PNG and other image files, to compressToJPG and get back a Uint8Array[], one JPEG per page. Turn each into an object URL and you have a thumbnail grid. Use compressToJPGStream to paint each page the moment it is produced rather than waiting for the whole file.
Extract single pages
Once a document is exploded, "download page 7" is a Blob and an anchor click, the bytes are already local. No extract endpoint, no job to poll, no temporary file on someone else's disk.
Reorder and remove
The page list is a normal JavaScript array, so drag-and-drop, delete, rotate-the-order and undo are all your own code, instant, offline, and with no per-edit API call. The SDK is only involved again at repack time.
Repack to PDF or TIFF
compressToPdf returns a single PDF of everything you pass it; compressToTiff returns one multi-page TIFF. Same input array, two containers, the user picks the format at the end, not the beginning.
Extract → reorder → repack
The whole pattern, worker mode. Every method resolves to {STATUS, DESCRIPTION, DATA} and never throws, so the error handling is a status check rather than a try/catch.
// Worker pool build, pages fan out off the main thread, UI stays live const helper = new ImageWizHelper(); await helper.ready; await helper.initialize(LICENSE_BLOB); // ---- 1. LOAD ------------------------------------------------ const source = new Uint8Array(await file.arrayBuffer()); const info = await helper.readImageInformation(source.slice()); if (!info.STATUS) return console.error(info.DESCRIPTION); console.log(info.DATA.TOTAL_PAGES); // e.g. 12 // ---- 2. EXPLODE, one JPEG per page ------------------------- const burst = await helper.compressToJPG([source.slice()]); if (!burst.STATUS) return console.error(burst.DESCRIPTION); let pages = burst.DATA; // Uint8Array[], page 1..n pages.forEach(p => renderThumb(URL.createObjectURL( new Blob([p], { type: 'image/jpeg' })))); // ---- 3a. EXTRACT, hand one page to the user ---------------- save('page_3.jpg', pages[2], 'image/jpeg'); // ---- 3b. REORDER / REMOVE, plain array work, no SDK call --- const order = [3, 0, 1]; // keep pages 4, 1, 2, in that order pages = order.map(i => pages[i]); // ---- 4. REPACK ---------------------------------------------- await helper.SetDPI(200); // .slice() each page, the worker TRANSFERS input buffers and // detaches them here. Keep the originals if the user will edit again. const out = await helper.compressToPdf(pages.map(p => p.slice())); if (out.STATUS) save('reordered.pdf', out.DATA, 'application/pdf'); else console.error(out.DESCRIPTION); // same array, TIFF instead: // await helper.compressToTiff(pages.map(p => p.slice()));
The gotcha: transferred buffers are detached
In worker mode the facade transfers input ArrayBuffers into the worker, which detaches them on the caller's side, the Uint8Array you passed in is empty afterwards. A page organizer feels this immediately, because the user repacks, then reorders, then repacks again from the same page bytes. Pass a copy (p.slice()) of anything you intend to keep, or re-read the file. It bites the source buffer too, that is why the readImageInformation call above is handed source.slice(): pass it the raw source and the explode step behind it would find nothing left to read. Main-thread mode does not transfer, but copying is the portable habit, it lets the same organizer code run in either mode.
The parts you don't have to build
Nothing leaves the machine
The SDK is WebAssembly. Pages are split and rebuilt on the user's own device, no upload, no server round-trip, and it keeps working with the network off. Documents people are reluctant to hand over never have to leave.
Two run modes
A main-thread build for the simple case, one document, smallest setup, and a background worker-pool build that keeps the UI responsive while a long file explodes. Same method names, same response shape; you swap which file you load.
One response contract
Every method resolves to {STATUS, DESCRIPTION, DATA} and never throws across the API. A page that fails to decode is a STATUS: false with a message, not an exception through your drag-and-drop handler.
Decide what the rebuilt file looks like
The setters apply per page during the repack, so the same page array can produce a small grayscale archive copy or a full-resolution colour PDF depending on what the user picked.
- ✓ DPI, 100, 150, 200, 300, 500, 600, or any value
- ✓ Filter, Normal, Black & White or Grayscale
- ✓ Page layout, A0 through A6, or a custom pixel size
- ✓ Custom layout fits or stretches pages onto your canvas
await helper.SetDPI(300); await helper.SetFilter(201); // 0 · 200 BW · 201 Grey await helper.SetPageLayout(4); // 0..6 → A0..A6 // or a canvas of your own, aspect-fit: await helper.SetCustomPageLayout( 12, 1654, 2339, 0xFFFFFF00); const out = await helper.compressToTiff( pages.map(p => p.slice())); if (out.STATUS) save('rebuilt.tiff', out.DATA, 'image/tiff');
Questions
More on the SDK, its run modes and the full method list on the Browser JS SDK overview.