Seam Carving in Canvas: Resize by Energy
Generate an energy map, accumulate a seam cost, backtrack and remove one connected path, preserve masks, and export the PNG beside its recipe.
Seam carving JavaScript removes one connected low-energy pixel path instead of squeezing every subject or discarding a fixed edge. This tutorial builds a bounded vertical pass in Canvas with a visible energy map, deterministic dynamic programming, protection and removal masks, invariants, and a PNG-plus-JSON receipt.
Seam carving JavaScript removes a path, not a strip
Seam carving JavaScript resizes an image by finding a connected low-energy path from top to bottom and removing one pixel from every row. Unlike uniform scaling, it preserves the dimensions of the pixels that remain. Unlike a fixed crop, it can bend around high-energy subjects. That flexibility is also the risk: the algorithm can quietly distort faces, text, logos, and repeated geometry.
This tutorial builds one vertical-seam pass over a deterministic 96×64 generated poster. It computes an energy map, applies protection and removal masks, accumulates dynamic-programming cost, backtracks one seam, removes it from every aligned buffer, and exports a PNG plus a JSON recipe. Each stage is visible so the visual result never becomes the only evidence.
The original seam carving publication record introduced content-aware resizing through seams of low importance. Here, importance is an authored energy function rather than an objective property of the image. Gradients, masks, and penalties express what the tool should protect or invite removal around.
A useful implementation starts with one narrow contract: remove vertical seams only, from a bounded raster, while preserving dimensions, finite costs, mask alignment, and a deterministic receipt. Expansion, forward energy, video coherence, and semantic segmentation are valuable extensions, but mixing them into the first pass would hide the core seam.
- Generate or decode one bounded RGBA source.
- Compute finite gradient energy and apply bounded protection and removal penalties.
- Accumulate minimum cost with a published tie rule and parent direction.
- Backtrack exactly one in-bounds coordinate per row with adjacent horizontal steps.
- Remove that coordinate from image and every aligned mask.
- Export the presentation PNG beside a numeric recipe and seam hash.
Reading rule: labels, symbols, patterns, and structure carry the conclusion; color is supplementary.
Define the pixel and work budget
Decode the source into a Canvas-sized RGBA buffer and freeze orientation before analysis. Record width, height, color handling, alpha policy, and the exact energy version. The browser’s Canvas pixel-manipulation model supplies ImageData access; it does not define a content-aware importance metric or guarantee identical encoded PNG bytes across platforms.
Bound work before allocation. For width W and height H, one energy pass, one dynamic-programming pass, one backtrack, and one compaction are each O(W×H). Removing K seams by recomputing from scratch is O(K×W×H) with W shrinking over time. Cap source dimensions, seam count, mask count, and export size. Reject requests that would remove the protected minimum width.
Use typed arrays for energy, cumulative cost, parent direction, and masks. Keep the original RGBA source separate from derived views. Avoid building nested pixel objects; they amplify memory and make alignment bugs harder to spot.
The bounded approach complements Canvas dithering: both techniques need an explicit pixel domain, deterministic parameters, and a distinction between the numeric working buffer and the displayed preview. For seam carving JavaScript, every iteration should state old size, new size, seam energy, mask intersections, and elapsed work. If those numbers are missing, a plausible image can conceal an invalid removal.
Compute an inspectable energy map
Start with a luminance-based gradient. Convert neighboring RGB values to a declared luminance approximation, compute horizontal and vertical differences, and combine their magnitudes. Clamp border coordinates or assign a deliberate border penalty so the algorithm does not remove edges merely because a neighbor is missing. Store finite nonnegative values.
Energy is a design surface. High-frequency texture and text edges become expensive, while smooth backgrounds become cheap. That often matches intuition but can fail on a flat-colored face or an important quiet area. A protection mask adds a large positive penalty. A removal mask subtracts a bounded amount to attract the seam. The combined energy must remain finite; if negative costs are allowed, document them because they change how the cumulative ledger is interpreted.
Normalize only for display. The false-color heatmap may map low energy to dark and high energy to bright, but the dynamic program must consume the original numeric values. Export min, max, and selected probe values so a renderer change does not alter the algorithm.
Density-based art offers a useful contrast. Voronoi stippling from an image density field redistributes marks to represent a source; seam carving removes a connected path. Seam carving JavaScript should preserve this distinction. A beautiful energy map is not the deliverable—the path, dimensions, and protected intersections are.
Accumulate cost with dynamic programming
Let E(x,y) be the energy at a pixel. For the first row, cumulative cost M(x,0)=E(x,0). For each later row, M(x,y)=E(x,y)+min(M(x−1,y−1), M(x,y−1), M(x+1,y−1)), with out-of-bounds parents excluded. Save the winning parent direction for every cell.
Choose and publish a tie rule. Prefer straight, then left, then right, for example. Without a deterministic tie break, equal-cost synthetic regions can produce different seams across refactors even when every total is valid. The receipt should include the rule and a hash of the energy and seam arrays.
The improved seam-carving work on forward energy evaluates disruption introduced by a removal rather than relying only on existing gradient magnitude. This tutorial keeps the simpler backward-energy recurrence so each term fits in one figure. Treat forward energy as a versioned alternative, not an invisible upgrade.
Seam carving JavaScript benefits from a small recurrence lattice in the UI. Hover or step through one cell, its three eligible parents, the chosen predecessor, and its cumulative value. That turns dynamic programming from a magic heatmap into an inspectable decision. The attached lab renders the full cost map but limits the interactive example to one bounded raster.
- First row
- Cumulative cost equals local energy.
- Later rows
- Add local energy to the minimum valid upper-left, upper, or upper-right cumulative cost.
- Parent
- Store the winning direction using a deterministic straight-left-right tie rule.
- Backtrack
- Start at the minimum final-row cell and follow parents upward; the highlighted path must move at most one column per row.
Reading rule: labels, symbols, patterns, and structure carry the conclusion; color is supplementary.
Backtrack and remove aligned state
Choose the minimum cumulative cost in the last row using the same deterministic tie policy, then follow saved parents upward. Validate the path before mutation: exactly H coordinates, one per row; every x inside bounds; and each adjacent horizontal delta no greater than one. Count protection and removal-mask intersections.
Allocate new buffers with width W−1. For each row, copy every pixel except the seam coordinate. Compact the protection and removal masks with the exact same coordinate. If a mask keeps the old stride, the next iteration optimizes against the wrong subject while the preview still looks plausible.
After compaction, assert the new RGBA length equals (W−1)×H×4 and every mask length equals (W−1)×H. Recompute energy rather than attempting an incremental optimization in the first version. A local update can be faster, but it adds a larger invalidation surface around the removed path.
This same topology discipline appears in signed-distance-field typography: the displayed contour depends on a numeric field whose dimensions and sampling must remain explicit. A dynamic programming seam is less about a clever loop than about keeping image, field, masks, parents, and export metadata synchronized after every structural edit.
Compare scale, crop, and seam removal
Render three equal-size outcomes from the same poster: uniform scale, centered crop, and seam removal. Scaling preserves composition but changes object proportions. Cropping preserves local pixels but discards a fixed boundary region. Seam removal preserves remaining pixel dimensions but redistributes spatial relationships along a path. None is universally correct.
Inspect landmarks rather than only the thumbnail. Measure the width of protected subjects, distances between repeated verticals, circularity of round elements, text aspect ratio, and the fraction of the requested removal consumed by masked regions. A low total seam energy can coexist with a visible bent line.
Use overlays. Draw every removed seam on the original, animate them in order only when motion is allowed, and provide a static list or map. Stop the batch when a seam crosses a protected pixel, a distortion metric exceeds its threshold, or the target width would violate the work budget.
The poster workflow in OffscreenCanvas generative posters is a natural next step for larger previews, but worker execution does not improve algorithmic taste. Keep the same bounds and receipts across threads. Seam carving JavaScript earns its complexity only when the seam result is visibly better for the intended composition than the simpler scale or crop.
- Scale: preserves composition but changes all object proportions.
- Crop: preserves local pixels but discards a fixed boundary region.
- Seam removal: preserves remaining pixel dimensions but changes spatial relationships along a connected path.
- Decision: compare landmarks, protected intersections, and the intended composition; the lowest-energy seam is not automatically the best edit.
Reading rule: labels, symbols, patterns, and structure carry the conclusion; color is supplementary.
Add masks as explicit editorial instructions
A protection mask says “pay a high cost to remove this region.” It is not an absolute guarantee unless the penalty is proven larger than every alternative path across the full image. For product tools, present it as a strong preference and fail when any protected intersection occurs. An infinite sentinel complicates arithmetic; a finite documented penalty plus a hard post-check is easier to audit.
A removal mask says “prefer paths through this region.” Bound its negative bias so costs remain finite and the path cannot exploit an accidental numerical underflow. Track how many removal pixels the seam consumes. Clear or update the mask after compaction so a deleted target does not continue pulling future seams toward a stale coordinate.
Author masks at source resolution. Pointer coordinates from a scaled preview must be transformed back through the current display rectangle and device-pixel ratio. Record brush radius and coordinate transform in the recipe. Use keyboard-operable presets in addition to painting so the lab remains testable without a pointer.
The semantic duty resembles ASCII art renderer calibration: the transformation needs both a visual output and a human-readable account of what was preserved, lost, or approximated. Seam carving JavaScript should export masks and seam coordinates, not only a flattering PNG.
Export a reproducible resize recipe
The JSON receipt should include source recipe and hash, initial and final dimensions, energy function and border policy, mask shapes and penalties, tie rule, seam coordinates in removal order, per-seam cost, protected intersections, work caps, algorithm version, and numeric hashes. The PNG is a presentation artifact; the JSON is the reconstruction and review artifact.
Label browser-dependent boundaries. Canvas color conversion, antialiasing in displayed overlays, and PNG encoding may vary. The deterministic part of this lab is the generated source buffer, the numeric energy and dynamic-programming arrays, the seam path, and the declared compaction. Hash those values before encoding.
Revisit the implementation when adding horizontal seams, multiple-object removal, forward energy, worker execution, or user-provided images. Each change affects the contract and deserves new fixtures. Keep a tiny synthetic case where the correct seam is obvious, a tie case, a protected-column case, and a removal-mask case.
That makes seam carving JavaScript an inspectable content-aware image resizing tool rather than a visual trick. Its Canvas energy map and protect and remove masks expose where geometry bends and admit when a crop is better. Open the lab, generate the poster, apply both masks, remove one seam, and keep the PNG beside its recipe.
Runnable local artifact — The lab removes one vertical backward-energy seam from a generated poster; it is not a production photo editor, semantic saliency model, forward-energy implementation, or proof of perceptual quality.
Generate the source, compute finite gradient energy plus bounded masks, accumulate deterministic parent costs, validate the path, compact every aligned buffer, and export the recipe.