Caption a picture with text that is measured, wrapped and kept inside the frame. The preview canvas is the exported file, pixel for pixel.
Initializing in your browser…
Resize with the filter named (Lanczos, Mitchell, Catmull-Rom, bilinear, box or nearest) and the option to average LIGHT rather than stored bytes, which is worth 1.24 stops on a detailed picture.
Read text off a picture with Tesseract, after preparation that measures the type and enlarges it: 8px text went from a 53 percent character error rate to 8. Every word carries a confidence and a box drawn on the picture.
Twelve procedural patterns that tile exactly, verified live with a measured wrap error and a 3 by 3 repeat view. Perlin, fractal, ridged, Voronoi, marble, wood and geometric grids.
A 600 by 400 picture with the default TOP TEXT and BOTTOM TEXT captions, measured on screen and in the file.
Input
wm-ground.png 600 x 400 · Impact 48 px · 3 px outline
The preview against the downloaded file
before after type drawn on screen 16 px 48 px type drawn in the file 48 px 48 px caption width, screen/file 0.44x 1.00x pixels differing 19,754 0 of 240,000 240,000 96 px caption, 52 characters ran off both edges yes no lines 1 4
The old preview drew its text at `fontSize / 3`, a hardcoded divisor, so it matched the file only when the displayed picture happened to be exactly a third of the real one. It is now one canvas drawn by one function at two scales, and the two are byte identical. Nothing called measureText either, so a long caption ran off both edges; captions are now measured, wrapped and brought down in size until they fit.
Caption a picture with text that is measured, wrapped and kept inside the frame. The preview is a canvas drawn by the same function that writes the file, so the two are identical pixel for pixel. PNG, JPEG or WebP, entirely in your browser.
Caption a screenshot in the classic white-on-black-outline style and drop the PNG straight into a channel.
Put a long caption on a photograph and let the wrapping and the shrink keep every word on the picture.
Label a picture with a caption whose position and size you can read off the page in the picture’s own pixels.
Upload a picture, keep the two default captions, type into each, and download. The type is Impact at 48 px with a 3 px black outline, anchored 4 percent from the top and 4 percent from the bottom, and the file is the picture at its own resolution.
Type a 52-character line and put the size up to 96 px. It wraps onto four lines at 92 percent of the width and the type comes down to 72 px, and the exported file has no ink within 4 percent of either edge.
A meme generator makes one promise: the picture on screen is the picture in the file. This version keeps it literally. The preview is a canvas drawn by the same function as the export, at a smaller scale, and a test asserts the two are identical pixel for pixel rather than merely similar. The previous version drew its canvas text at the size you asked for and its preview at `fontSize / 3`, a hardcoded divisor, so the two agreed only when the displayed picture happened to be exactly a third of the real one. Measured on a 600 by 400 picture shown at 450 by 300: the display scale is 0.75, so 48 px type should have appeared at 36 px and appeared at 16, and the exported caption came out 2.25 times as wide and 2.03 times as tall as the one on screen. The two pictures differed on 19,754 of 240,000 pixels.
Captions are measured before they are drawn. Nothing in the old tool ever called measureText, so nothing wrapped and nothing stayed on the picture: a 52-character line at 96 px ran off both edges of a 600 px wide export. Every caption here is measured by its INK (`actualBoundingBoxLeft` and friends) rather than by its advance width, wrapped to a width you set as a share of the picture, laid out on the FONT’s own line height rather than on the point size, and, with Shrink to fit on, brought down a pixel at a time until the whole block sits inside the frame. The page says which of those happened and by how much: the block size, the size it was drawn at, the line height, the distance from each edge, and a note for every wrap, shrink or nudge.
The outline is a real stroke on both sides now. A canvas stroke is centred on the glyph outline, so half of it falls inside the letter and a visible outline of N pixels needs a line width of 2N; the export always did that correctly and the preview wrote four one-pixel `text-shadow` offsets whatever the setting, which is not a stroke and did not change with the slider. Every line’s outline is drawn before any line’s fill, so a tight line spacing cannot put one caption’s outline on top of another’s face.
One detail is worth knowing because it is not obvious: Chromium does not rasterise text identically into a canvas that is in the document and one that is not. Measured here, the same strokeText and fillText calls differ by up to 210 of 255 at the glyph edges, which is the difference between an accelerated and a software raster. The export canvas is therefore attached to the document off screen while it draws, which is what turns “the preview matches the file” from a tolerance into an identity.
Captions carry their own font, size, colour, outline colour and width, horizontal alignment, vertical anchor, uppercase, wrapping, line spacing and shadow, and are dragged straight on the preview: the pointer position is converted through the canvas’s bounding rectangle, so a caption lands exactly where it was dropped whatever size the canvas happens to be displayed at. Five layout presets rearrange the captions; there are no bundled meme photographs, and the page no longer claims any. Output is PNG, JPEG or WebP, named after the picture you uploaded, with a quality slider that appears only where quality does something.
Yes, and it is one function rather than two: the preview calls the same drawing code at a smaller scale, and the test suite asserts the preview canvas and the exported file are identical pixel for pixel. The previous version drew the preview at a third of the size whatever the picture was, and the two differed on 19,754 of 240,000 pixels on an ordinary 600 by 400 image.
No photographs are bundled; upload your own picture. What the Layout buttons give you are caption arrangements: top and bottom, bottom only, top only, centred, and two panels. The previous version listed five meme names in its code and applied none of them.
It wraps to the width you set, and with Shrink to fit on the type comes down until the whole block is inside the picture. The panel under the preview says how many lines it wrapped onto and what size it settled at. Nothing runs off the edge.
A canvas stroke is centred on the glyph outline, so half of it falls inside the letter. The number on the slider is what you see on each side, and the tool passes twice it to the canvas. The label shows both.
Yes. Uppercase is a per-caption toggle and it is on by default because that is the convention; turn it off and your text is drawn as typed.
No. The picture is decoded, drawn and encoded in your browser, and nothing leaves the machine.
Images are decoded, edited, and exported entirely inside this browser tab. No originals, exports, or metadata are uploaded.