Batch conversion · in the tab · nothing uploaded
Every file,
converted in the tab.
Drop files, a folder or a ZIP. This desk reads the first bytes of each one and tells you what it actually is rather than what it is called — then converts the batch: images and text through the browser’s own machinery, audio and video through FFmpeg. Every file in the list can overrule the batch on format, size and quality.
Nothing you pick leaves this tab. There is no endpoint on this property to send a file to. The one request this page can make goes the other way: press the engine button and about ten megabytes of compiled FFmpeg travels from unpkg.com into the tab, where it stays until you close the page. That is code coming in, not your file going out, and the page names the files and the sizes before you press it.
0files queued
0 Bread into this tab
—image formats this browser can write
—longest canvas edge this browser paints
The queue
Four ways in, and the bytes read on the way.
Pick files, pick a folder, pick a ZIP, or drop any of the three onto the page — a dropped folder is walked to the bottom and a dropped ZIP is unpacked, the same as choosing one. Every file is then measured: the real type from its signature, the real dimensions from its header, the real duration, the real encoding. Where the name and the bytes disagree, the row says so.
The queue
Nothing queued yet. Everything below is measured from real files, so the list stays empty until there are some.
The settings
A default for the batch. An answer for any one file.
What is set here is what the batch does unless a row says otherwise. Open any row’s detail and it can take its own format, its own dimensions, its own quality — and the row shows that it has. Every setting on this page is remembered in this browser and nowhere else. The queue is not: close the tab and the list is gone, because the files were never anywhere but in it.
Images — through the canvas
An exact width and height ignores the original ratio, so the picture is stretched. Fitting an edge never does.
Testing what this browser can write…
Applies to JPEG, WebP and AVIF. PNG is lossless and ignores it.
JPEG has no alpha channel, so a picture with transparency in it has to land on something. This is what. PNG, WebP and AVIF keep the alpha and ignore this; a row whose picture is about to be flattened says so before the run.
An SVG has no pixels until something draws it. The height follows the viewBox.
Video — needs the engine
A GIF is built from the first seconds only, with a palette generated from the clip itself. It is a palette of 256 colours; a photograph-like clip will band.
The frames are written as PNG and land in a folder of their own inside the ZIP.
Audio — needs the engine
Ignored by WAV and FLAC, which are lossless and take whatever the source gives them.
Text and tables
CSV, TSV and JSON are read as real tables — quoted fields, embedded commas, embedded line breaks and doubled quotes all handled to RFC 4180 — and can be written back out as any of the tabular kinds. Which character separates the fields is read off the file rather than off its extension, so a semicolon table — what Excel writes across most of Europe — is not flattened into one column. A file that is not a table is skipped rather than mangled, and the row says so. “Copy the file unchanged” is the only text setting that touches nothing: the others decode the bytes and write UTF-8 back, which removes a byte-order mark and re-encodes anything that was not UTF-8.
Naming
{name} the original name without its extension ·
{ext} the new extension ·
{w} and {h} the output dimensions ·
{index} its place in the queue ·
{date} today, as 2026-01-31.
A token with nothing to fill it leaves nothing behind, and the
stray separator it would have left is tidied. The extension is
appended if the pattern forgets it.
Queue a file and the pattern is shown against its real name.
Canvas work only. FFmpeg is one engine and cannot be asked two things at once, so audio and video always queue behind themselves.
What this browser was measured to be able to do
Measuring…
Not read off a version number. Each write is tested by drawing one pixel, asking the canvas for that format, and sniffing the bytes that come back; each read is tested by decoding a small file of that format. The orientation questions are answered with two 677-byte photographs, sixteen pixels by eight, that carry nothing but a rotation tag.
The run
Start it, watch it, stop it.
One file failing marks that row and the run carries on. Cancel stops it rather than hiding it: whatever has not started is marked skipped, with the reason.
The run
The FFmpeg engine — for audio and video only
Images and text need nothing but this page. Audio and video need FFmpeg, which is not part of this page and is fetched when you press the button. Pressing it downloads, from unpkg.com, these files:
- @ffmpeg/ffmpeg@0.12.10 — the class and its worker, about 13 KB
- @ffmpeg/core@0.12.6/ffmpeg-core.js — 114,494 bytes
- @ffmpeg/core@0.12.6/ffmpeg-core.wasm — 32,129,114 bytes, served compressed at about 10.2 MB
Those figures were measured against unpkg.com on 19 August 2026 and are what the page was built against; what your browser actually transfers depends on what it has already cached. The direction matters more than the size: this is compiled code arriving in your tab. No file of yours goes anywhere, then or ever. The engine lives in the tab until the page is closed.
Not loaded. Images and text convert without it.
0 of 0 handled
The ledger
In, out, and what happened to each one.
Every figure below is the real byte length of the real file, read after it was written. A saving is the difference between the two, never a projection, and a file that came out larger is shown as larger.
Results
Nothing has been run yet.
| File | In | Out | Change | State | What was done, or why not |
|---|
About
What runs where, and what this desk will not do.
Images and text are converted by the browser itself. A picture is decoded, drawn onto a canvas at the size you asked for, and asked back out as PNG, JPEG, WebP or AVIF; text is decoded, parsed if it is a table, and written out again. None of that leaves the page.
Audio and video are converted by FFmpeg compiled to WebAssembly. That engine is not part of this page: pressing the button downloads it from unpkg.com — about 10 megabytes across the network, thirty two in the tab — and it then runs here, in a worker, on files that never leave. The page names the exact packages and sizes above the button rather than after it.
No file you pick is ever uploaded. Not to labs.llc, not to unpkg, not anywhere. This property has no upload endpoint and makes no request carrying your files, their names, or anything read out of them. It is worth being exact about the rest: this page carries the same Google Analytics tag every page on labs.llc carries, and that tag reports the address of the page, its title, the size of the window and a visitor identifier — the ordinary things a web analytics tag reports, and nothing about your files, because nothing on this page ever hands it any. Everything you choose here — formats, sizes, the naming pattern — is kept in this browser’s local storage under one key belonging to this page.
A canvas re-encode discards EXIF, and the GPS tags with it. That is a privacy feature and it is worth saying plainly: a photograph from a phone often carries the coordinates of where it was taken, and this page will tell you which of your files do. It never reads the values and never shows them. Converting such a file removes them. Copying it unchanged does not — that is what “copy the file unchanged” means, and it is the honest choice for keeping a picture intact rather than for stripping it.
A canvas hands back sRGB, and nothing else. Any colour profile embedded in a picture is dropped by the re-encode: a Display-P3 or Adobe RGB image comes out with its numbers intact and nothing left to say what they meant, which most viewers will then read as sRGB. A CMYK or YCCK JPEG — the kind that comes back from a printer — is converted to sRGB on the way through and cannot be converted back here. The row says so before the run and the ledger says so after it. Copying the file unchanged is the only way through this page that keeps either.
JPEG has no alpha channel. A picture with transparency written as JPEG has to land on a colour, and the setting that chooses it is beside the quality slider, set to white until you change it. The row warns before the run and names the colour; the ledger records it afterwards. PNG, WebP and AVIF keep the alpha.
Re-encoding a lossy image loses more. JPEG, WebP at default quality and AVIF all throw information away to be small. Doing it again throws more away, even at quality 1.0, and no setting on this page can put it back. If a picture only needs a different container, copy it unchanged. If it only needs to be smaller on disk and you have the original, convert from the original rather than from an earlier conversion.
What this desk will not do. It is not a PDF toolkit: it will name a PDF correctly and refuse to convert it. It does not edit video — there is no trimming, no joining, no filters beyond a scale and a frame rate. It cannot convert a format the browser cannot decode, which for most browsers means HEIC from an iPhone; the capability table above says which ones yours can read, measured rather than guessed. An animated GIF or WebP redrawn through a canvas keeps only its first frame, and the row warns before the run rather than after. It cannot develop a raw file from a camera — it will name one as the TIFF container it is and go no further, because the sensor data sits in a private tag no browser decodes. It does not open Photoshop or Office documents either, and it will say what each one is instead of pretending otherwise.
The ZIP reader and writer is JSZip 3.10.1, served from this site rather than from a content network, because reading and writing archives is core to what this page is for and should not depend on somebody else’s uptime. It is 97,630 bytes and it is fetched the first time an archive is read or written rather than on every visit, so a page that only converts a photograph never asks for it. An archive is unpacked up to four levels deep, and this page will decompress a gibibyte and queue twenty thousand members out of one before it stops and says which limit it reached — a small archive of nothing but zeroes expands about a thousand to one, and a tab has to be able to say no to that.