Understanding browser image editing
Canvas, pixels, and one trip to the GPU.
What in-browser image editing actually is, the canvas pipeline that does the work, and why the saved file isn't the same as the file you opened.
Three pieces.
Browser image editors are built from three pieces. An HTMLCanvasElement (a 2D drawing surface), the 2d context (the API for drawing on it), and either filters/CSS or pixel-level ImageData manipulation for effects. Open an image, draw it onto a canvas, apply transforms (crop, rotate, scale, filter), read the canvas back as a PNG or JPEG blob. That's the whole loop.
Crop is a coordinate problem.
The crop operation: ctx.drawImage(source, sx, sy, sw, sh, 0, 0, dw, dh) — copy a rectangle from the source image into the destination canvas, optionally resizing. Setting the canvas dimensions to the crop rectangle's size and copying from the source rectangle to position (0,0) is the entire crop. No new file format, no library, just one drawImage call.
Filters — fast and slow paths.
The fast path: ctx.filter = "grayscale(100%) blur(3px) contrast(1.2)" — CSS filter syntax applied to subsequent draw operations. The browser uses GPU- accelerated rendering; near-instant on any size. The slow path: read ImageData back, manipulate the Uint8ClampedArray of pixel values directly, write it back. Used for effects CSS doesn't have (a colour-replace, a custom convolution kernel, channel swap). Roughly 50× slower for the same throughput.
A worked rotation.
Rotating an image by 45°: set the canvas dimensions to the bounding box of the rotated image (slightly larger than the original), translate the origin to the centre, rotate by the angle, draw the image at (-w/2, -h/2) so it comes out centred. The maths is the same as PDF watermark rotation; only the drawing surface differs.
Rotate around centre
translate → rotate → drawImage(-w/2, -h/2)
Move origin to centre, rotate, draw image offset.
ctx.translate(W/2, H/2) → ctx.rotate(rad) → drawImage(-w/2, -h/2)
= Centred rotated image
Save loses metadata.
Encoding the canvas as JPEG or PNG strips most of the original file's metadata. EXIF (camera model, GPS, capture time), ICC colour profile, custom XMP fields — all gone unless the editor specifically copies them across. For most use cases this is fine (and arguably desirable from a privacy standpoint), but it means "edit and save back" isn't lossless. Photo editors aimed at photographers preserve metadata explicitly; quick-edit tools usually don't.
JPEG quality, the slider.
When saving as JPEG, the second argument to toBlob / toDataURL is a quality value between 0 and 1. Default is around 0.92. Lower means smaller file and more compression artifacts; higher means larger and cleaner. Photos at 0.85 are visually indistinguishable from 0.95 for almost all viewers but half the file size. PNG has no quality dial — it's lossless; saving as PNG always produces the same image data.
Privacy by construction.
Browser image editing keeps the image local. The file is read into the canvas, manipulated, and emitted as a download — nothing uploaded. For sensitive images (medical scans, ID cards, screenshots of confidential systems) this is a meaningful property. The same operations on a cloud-hosted editor put copies of the image on someone else's storage; the local-canvas version doesn't.