Two hundred files in a browser
A tab is a real program with a budget somebody else set. This is where that budget runs out, what it looks like when it does, and the size of job at which you should be writing a script instead.
The only arithmetic that matters
A photograph on disk is compressed. To change its size it has to be uncompressed into a grid of pixels, and that grid is four bytes per pixel no matter how small the file was. Everything about the ceiling follows from that one conversion:
a 12 MP phone photo 4032 × 3024 = 12.2 M pixels ≈ 49 MB decoded
a 24 MP camera file 6000 × 4000 = 24.0 M pixels ≈ 96 MB decoded
a 45 MP camera file 8192 × 5464 = 44.8 M pixels ≈ 179 MB decoded
on disk, each of those is between 3 MB and 60 MBThe run opens several files at once — one per worker, up to six — so the number to hold in your head is that product. Six 24-megapixel files being worked on simultaneously is about 600 MB of live pixels before the outputs, which is comfortable on a laptop with headroom and is most of a phone’s entire allowance.
Three things deliberately do not scale with the length of the queue, and they are why a thousand files is possible at all:
- Queuing reads sixty-four kilobytes per file and decodes nothing. A folder of a thousand costs a few megabytes to list, measure and plan.
- A source is decoded once and all of its outputs are written from that one decode before the worker lets go of it. Four outputs per photograph cost one decode, not four.
- Finished outputs go straight into the archive as handles the browser stores for itself. The ZIP grows on disk rather than in the tab.
So queue length is cheap and pixel dimensions are expensive. Two thousand web-sized images are easier than eighty raw-converted 45-megapixel files, and file count is the wrong thing to be nervous about.
Where each machine gives up
| Machine | Comfortable | Pushing it | What running out looks like |
|---|---|---|---|
| Laptop or desktop, 16 GB | a few hundred camera files | a thousand or more | Slowing down, then a failed row with a reason. The run continues. |
| Older machine, 4–8 GB | a hundred or so | a few hundred | Swapping. Everything on the machine gets slow before anything here fails. |
| Chromebook or low-end tablet | a few dozen | a hundred | Individual large files refused; small ones keep going. |
| iPhone or iPad | a few dozen small files | do not | The tab is discarded. No error, no partial archive, the page simply reloads. |
The last row is the one that costs people work, and it is not a matter of degree. Every other platform here degrades: a file fails, the ledger says why, and the remaining files are written. Safari on iOS reclaims the whole tab instead, and it does so without telling the page first, so there is nothing to catch and nothing to save. A run that would take three minutes on a laptop can end at file 140 on a phone with nothing written at all.
Refusals are not failures
A single image past about a hundred megapixels is refused on its own line, mid-run, with its reason in the ledger, and the rest of the queue carries on. Above a lower threshold the run asks once, before it starts, whether it may work from lighter copies of the largest sources — outputs smaller than the copy are identical either way. Both of those are the run protecting itself rather than the run breaking, and the distinction is visible in the ledger: a refusal has a reason next to it.