PAGE ORGANIZER · BROWSER JS SDK

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.

Runs on the user's device No uploads Works offline Images & PDF in, PDF/TIFF/JPEG out
THE LOOP

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.

1
Load

Read the file into a Uint8Array. Call readImageInformation for page count and per-page size, colour type and DPI.

2
Explode

compressToJPG fans a PDF, TIFF or image file out into one JPEG per page, an ordinary array you can render as thumbnails.

3
Reorder & remove

Your UI reorders or filters the array. No SDK call, the pages are already just bytes sitting in memory.

4
Repack

Hand the surviving pages, in their new order, to compressToPdf or compressToTiff to rebuild one document.

WHAT YOU CAN BUILD

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.

CODE EXAMPLE

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.

organizer.js
// 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.

HOW IT RUNS

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.

REPACK CONTROLS

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
repack.js
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');
FAQ

Questions

Can I split a PDF in the browser without uploading it anywhere?
Yes, that is the point of this SDK. It is WebAssembly running on the user's own device, so the file is read, exploded, reordered and rebuilt locally. There is no server round-trip and no upload, and the whole flow keeps working offline once the page is loaded.
How do I extract pages from a multi-page TIFF in JavaScript?
Read the file into a Uint8Array and pass it to compressToJPG. Multi-page TIFF and PDF inputs fan out per page, and DATA comes back as a Uint8Array[], one JPEG per page. Each entry is an ordinary byte array, so wrapping one in a Blob and triggering a download is all "extract page 7" means. readImageInformation tells you the page count up front.
How do I rearrange PDF pages client side?
Reordering is your code, not an SDK call. After the explode step the pages are a JavaScript array, so drag-and-drop, delete and undo are array operations. When the user is done, hand the array, in its new order, minus the removed entries, to compressToPdf and you get one PDF back in exactly that order.
Why are my page buffers empty the second time I repack?
The worker facade transfers input ArrayBuffers to the worker, and a transferred buffer is detached on the caller's side afterwards. If you pass your retained page bytes straight into compressToPdf, they are gone for the next round. Pass a copy, pages.map(p => p.slice()), or re-read the source file if you need the bytes again.
Can I rebuild as a TIFF instead of a PDF?
Yes. compressToTiff takes the same array of page buffers and returns a single multi-page TIFF; compressToPdf returns a PDF. Both accept whatever you pass, so the output container is a decision the user makes at the end. There is also an append method that adds one document's pages onto the end of an existing TIFF, if you are growing a file rather than rebuilding it.
Will a 200-page file freeze the UI?
Not in worker mode. The background worker-pool build runs the explode off the main thread, so the thumbnail grid stays interactive while pages are produced. One document is one task on one worker, the pool's parallelism is what pays off when the user hands you several files at once. compressToJPGStream goes further and delivers each page as it is produced instead of all at the end, so thumbnails appear progressively. The main-thread build is simpler but will block on large jobs.
What happens without a licence?
Everything still runs. Initialisation is non-fatal, with a missing or rejected licence blob the SDK still initialises and every operation still works, but output carries a watermark band. That makes it easy to build and demo the whole organizer before licensing. Talk to us about licensing when you're ready to ship.
Do I need try/catch around every call?
No. Every method is async and resolves to {STATUS, DESCRIPTION, DATA}; failures never throw across the API. Check STATUS and read DESCRIPTION when it's false. DATA is only present on success.

More on the SDK, its run modes and the full method list on the Browser JS SDK overview.

Build the organizer, keep the documents local

Get a key and have pages exploding in the browser this afternoon.