You have one photograph of the workshop. The blog header wants it 1600 by 600. The category grid wants 400 by 400. The story card on the phone wants 1080 by 1350, taller than it is wide. The picture came off the camera at 3 by 2.
Crop it to the header and the person at the left edge is gone. Stretch it and everyone in the frame grows about ten centimetres. Letterbox it and you have paid for a header that is one third grey bar.
There is a fourth answer, nearly twenty years old. Instead of cutting a rectangle out, or scaling every pixel at once, you remove single wiggly columns that run top to bottom through the parts of the frame where nothing much is happening. Do it four hundred times and the picture is four hundred pixels narrower. The sky and the floor have given up the room. The people are still the shape they were.
The three usual answers and the bill for each
Cropping is what WordPress does on a hard crop. add_image_size() takes a fourth argument, $crop: false scales the image, true crops to the given dimensions using centre positions, an array names the corner, 'left', 'center' or 'right' on the x axis and 'top', 'center' or 'bottom' on the y, both defaulting to 'center'. Nine anchor points, and the size your theme registers applies them to every photograph alike.
Squashing is what CSS does when nobody stops it. The initial value of object-fit is fill, which sizes the content to fill the box and, when the ratios do not match, stretches it to fit. cover keeps the ratio and clips. contain keeps the ratio and letterboxes. Same three bills in CSS or in an editor: clipped means content gone, stretched means proportions falsified, letterboxed means space bought and not used.
Seam carving pays a fourth kind of bill. It keeps the framing and the proportions of anything with detail in it, and spends the difference out of the quiet regions: sky, wall, water, studio backdrop. Where there is enough quiet it is close to free. Where there is not, it deforms things visibly, which is the interesting part.
The tool below carves. Drop in a photograph, pull the width slider, watch which columns it decides it can live without. Nothing is uploaded: no fetch, no XHR, no beacon, not even an external font. The file is read out of the browser’s own memory and never leaves the page, which matters, because the pictures people reshape are client work, product shots and family photographs.
Content Aware Resizer
Change the shape of a photo by taking out the pixel seams that carry the least detail, instead of squashing it or cropping the edges off. The energy picture, the dynamic programme behind every seam and the finished file are all worked out in this browser tab: nothing is uploaded, nothing is fetched, nothing leaves your machine.
or press Enter to pick one. The picture on screen until then is drawn in this browser, no photograph is fetched.
No picture yet.
No picture yet.
The order of the seams is worked out once, up front, so the sliders can run forwards and backwards afterwards without a second pass.
Protect adds a very large number to the energy of every pixel you paint, remove subtracts an equally large one, so the search walks around the first and straight through the second. Painting changes the answer, so the seam order is worked out again when you let go.
| Seams taken out or doubled | n/a |
| Working size, before and after | n/a |
| Delivered size after scaling back | n/a |
| Operations counted while ordering the seams | n/a |
What a seam is
The technique comes from a 2007 SIGGRAPH paper by Shai Avidan and Ariel Shamir, “Seam Carving for Content-Aware Image Resizing”. Their definition is worth reading slowly: a seam is an optimal 8-connected path of pixels running top to bottom, or left to right, where optimality is defined by an image energy function.
So a vertical seam takes one pixel from every row, and because the path is 8-connected, that pixel sits above, above left or above right of the one taken below. It wanders a column at a time, never breaks, never skips a row. That is what lets you delete it: pull everything right of the seam one place left, each row independently, and the picture is a pixel narrower with no hole in it, one shift per row at unchanged stride. Everything else is which path to take.
Energy is the local gradient, nothing more
Energy is one number per pixel saying how much is going on there. The tool uses the Sobel operator, a discrete differentiation operator computing an approximation of the gradient of the image intensity function. Two 3 by 3 kernels are convolved with the picture, one measuring change across it and one down it, and the results combined by Pythagoras.
Gx Gy
-1 0 +1 -1 -2 -1
-2 0 +2 0 0 0
-1 0 +1 +1 +2 +1
E(y,x) = sqrt(Gx*Gx + Gy*Gy) computed on luminance
Over a cloudless sky every window of nine pixels looks like its neighbours, both sums come out near zero, and so does the energy. Across the edge of a roof Gy is large. Colour is thrown away first: the operator works on one brightness value per pixel, so a red poppy on equally bright green grass is nearly invisible to it.
Border pixels have no neighbour on one side, and treating the missing one as black lights the whole frame up as a giant edge, so no seam touches the border and every cut is pushed inward. The tool replicates the border instead: an edge pixel is compared against a copy of itself and stays as quiet as the region it sits in.
Why a table and not a search
Count the candidates. A vertical seam through a picture 1200 rows tall makes 1199 steps, each one of three choices, so one starting column offers three to the power of 1199 paths. That number has 573 digits, and there are as many starting columns as the picture is wide. Nothing tries them all.
Dynamic programming turns it into one pass. Build an array M the size of the picture and fill it from the top row down. The first row is the energy. Every row after gets the cell’s own energy plus the cheapest of the three cells above that could have led there. When the bottom row is done, its smallest value is the cost of the cheapest seam in the picture, found in one visit per pixel.
Reading the seam back out is the part people implement twice: walk up from the bottom, looking again at the three cells above. The tool does not. While filling M it writes a second byte array recording which predecessor won, so the traceback walks stored answers. One byte per pixel, one pass removed.
Removing a seam changes the energy of very little, since only pixels beside the cut have new neighbours, so Sobel is recomputed in a four column band around it. The table still has to be refilled, because one changed cell changes everything below it, and that is where the time goes: in headless Chromium the tool measured 35.25 million cell visits in 220 ms, roughly 160 million per second.
The rank card, or why the slider does not stutter
Carving 300 seams for a header, then dragging back ten and forward again, would mean carving 300 seams three times. Instead the order of every seam is computed once into a rank card: per pixel, the number of the seam that claims it. Rank 7 means the seventh seam takes it. A pixel nothing takes keeps a rank past the end.
Any reachable width is then a threshold: for 120 seams gone, keep the pixels ranked 120 or higher, one line at a time. The five ratio buttons, 16:9, 3:2, 4:3, 1:1 and 4:5, plus Original shape, move both sliders to the nearest reachable point on the card. The slider runs both ways at the speed of a memory copy, because nothing is decided any more, only read. The same card drives enlarging: inserting the cheapest seam and repeating just finds that seam again and smears a column, so the k cheapest are doubled together in one pass, each inserted pixel the mean of its neighbours. Height transposes the picture rather than duplicating the code, and its card is only paid for when you first move that slider.
Moving both sliders is the one place the tool approximates. Two rank cards on the same original cannot compose exactly, because removing a vertical seam changes which horizontal seam would have been cheapest. So the other axis’s card rides along as a companion array through the first pass, and the second pass picks the k smallest carried ranks per line from a histogram, ties from the left. That always hits the exact output size while approximating true alternating removal. On a difficult picture, carve one axis at a time.
All of it runs in a Web Worker built out of the very same functions, the pixel buffers handed over as transferable objects: an ArrayBuffer is transferable, so the memory block moves between threads in a zero copy operation and the original is left detached. The same code path exists synchronously as a fallback, and whether the Worker answers is remembered once instead of timed on every brush stroke.
Where it falls apart
Faces are the famous failure and the reason is the definition of energy. A cheek is smooth. A forehead is smooth. Eyes, nostrils and the mouth are high energy islands in low energy skin, so seams route around the features and through the skin between them. Take enough and the eyes move closer, the nose narrows, and it is subtly the wrong face. Nobody can say what changed, everybody sees that something did.
Straight architecture fails differently. A window frame is high energy and survives, the plaster between two windows is not, so the spacing shrinks while the windows do not. And a long straight line crossing a removed seam gets a one pixel step. One step is invisible. Three hundred in the same wall read as a bend, and the building appears to lean.
Regular patterns fail for the opposite reason: everything costs the same. Brickwork, roof tiles, a striped awning, a row of identical chairs. Cumulative costs across the pattern are nearly equal, the choice between one unit and the next is rounding, and the seams eat a bit here and a bit there until the rhythm is gone. The eye is very good at rhythm, so this is the artefact people notice first.
None of it is a bug. The method rests on one assumption, that a low gradient means unimportant, and skin, wall spacing and rhythm are exactly the places where that is false.
Painting is editing the energy map
The brush is where you tell the algorithm something it cannot work out. It is not a mask over the result but an additive layer on the energy: protect adds 100000 to a painted pixel, remove subtracts 100000. Against Sobel values in the low hundreds those are absolute. No path can afford to cross a protected region, so it survives intact while the rest of the frame gives up the room, and a region painted for removal is so cheap that the first seams all run through it, which is object removal for free. The paper made both points: the energy function can take user input, and object removal is one use of it.
The brush is sized from 4 to 90 working pixels, meaning pixels at the resolution the carving happens at, not your original file’s. Clear the paint and the map goes back to plain Sobel. Painting invalidates both rank cards, since the order of every seam has changed. Protecting fixes two of the three failure cases: paint the faces and the group photo survives a header ratio it had no right to, paint the window bay and the facade stops leaning.
What it deliberately will not do
There is a hard ceiling and it is arithmetic, not caution. The picture is carved at 1200 px on the long side, with a budget of 250 million cell visits and at most 320 seams per axis. Those numbers fit each other: 320 seams out of a 1200 by 800 picture, counting the table shrinking as it goes, is just under 246 million cell visits, while 400 seams on a three megapixel original would be 1.2 billion and a phone stops. The result is scaled back to the size the picture came in at, and the tool says so underneath.
- A picture under 8 px on a side is not carved at all and says so. Two pixels wide is left alone.
- A file that is not an image, or one the browser cannot decode, is refused by name and the previous picture stays on screen.
- Two copies of the tool on one page are not supported: the ids are fixed, as in every tool here.
- There is no face detection, no saliency model, no machine learning. The tool knows the gradient and what you painted, and that is the whole of its opinion about your photograph.
This is not the only browser doing this
Browser based seam carving has existed for years and some of it is good. Oleksii Trekhleb’s JS Image Carver is open source, runs entirely in the browser, cites the Avidan and Shamir paper, and gets object removal by lowering the energy under a painted mask, the same trick as above. Content Aware Scale Online runs a Rust port of the caire library compiled to WebAssembly, says plainly that no image data is sent to a server, and publishes its limits: 25 MB, 4000 by 4000 pixels, 2 to 10 seconds on a Web Worker.
The claim here is not novelty, it is the shape of the interaction. The rank card means both sliders scrub either way without recomputing anything, which turns carving from a job you submit into a control you pull, and the seam overlay and energy view let you watch the mechanism rather than trust it.
When to crop instead
A subject aware crop is right whenever geometry matters more than framing: screenshots, anything with type in it, product shots with straight edges, interiors, architecture, any picture whose subject already fills the frame. With no quiet region there is nothing to spend, and carving takes the difference out of something you cared about.
The size of the change matters too. Trimming a 3 by 2 photo to 16 by 9 is about a tenth of the height, and most pictures give that up without complaint. Turning it into a 4 by 5 story card is more than a third, a lot to ask of any sky, and there the honest answer is usually a crop with a chosen focal point, the approach behind responsive hero images. For a whole set of shapes from one asset, read the layout problem behind every social pack first.
Before any of it, know the number you are aiming at: the image size your theme actually wants and how big the file should be before upload. When the carved PNG goes back into WordPress in place of the original, replace the file instead of uploading a second copy, which is what the replace step in WunderPaint’s media library is for, so published links keep working.
What carving is actually for
Seam carving is not a better crop. It is a different trade, and what you give up is absolute geometric fidelity. Every seam removed is a broken promise about distances inside the picture. On a beach at sunset nobody collects on that promise. On a photograph of a building, someone will.
What makes it usable is that the failures are not random. They come from one assumption stated in one line of arithmetic, so once you know it you can predict the result before touching a slider. Smooth and important is where it hurts you, and the brush exists so you can name those regions yourself.
So, the workshop photograph. Protect the people, carve the width down to the header ratio, and let the empty half of the room pay for it. Take the square from a crop, because a third of the width is more than any quiet sky covers honestly. Shoot the tall one again, or build it as a composition. Three shapes, three decisions, and only one was ever really a technical problem.