Photo Merge — Java source
Combine photos side by side, stacked, or in a grid — uniform cells, adjustable gap, one PNG out. Runs entirely in your browser.
This is the Java implementation — the same logic the interactive tool runs, in a shareable, citable form.
// photo-merge — Java port: side-by-side merge cell layout.
import java.util.ArrayList;
import java.util.List;
/** A decoded image's dimensions. In the browser tool the bitmap is
* drawImage'd into its letterboxed cell; the geometry here is the
* deterministic part of that pipeline. */
record ImageSize(int width, int height) {}
/** Where one image lands on the merged canvas. */
record Placement(double scale, int x, int y, int w, int h) {}
record MergedLayout(int canvasW, int canvasH, List<Placement> placements) {}
public class PhotoMerge {
/** Mirrors mergeSideBySide in typescript.ts: cellW/cellH are the
* largest input dimensions, the canvas is n cells + (n + 1) gaps
* wide and one cell + 2 gaps tall, and each image is scaled by
* min(cellW / w, cellH / h) and centered inside its cell.
* Math.round rounds half up, matching JS exactly. */
static MergedLayout mergeLayout(List<ImageSize> images, int gap) {
int n = images.size();
int cellW = 0, cellH = 0;
for (ImageSize img : images) {
cellW = Math.max(cellW, img.width());
cellH = Math.max(cellH, img.height());
}
List<Placement> placements = new ArrayList<>(n);
for (int i = 0; i < n; i++) {
ImageSize img = images.get(i);
double scale = Math.min(
cellW / (double) img.width(),
cellH / (double) img.height());
int w = (int) Math.round(img.width() * scale);
int h = (int) Math.round(img.height() * scale);
placements.add(new Placement(
scale,
gap + i * (cellW + gap) + (int) Math.round((cellW - w) / 2.0),
gap + (int) Math.round((cellH - h) / 2.0),
w, h));
}
return new MergedLayout(
n * cellW + (n + 1) * gap, cellH + 2 * gap, placements);
}
public static void main(String[] args) {
// 800x600 + 600x800 + 1024x768 with a 12px gap -> 3120x824 canvas.
MergedLayout layout = mergeLayout(List.of(
new ImageSize(800, 600),
new ImageSize(600, 800),
new ImageSize(1024, 768)), 12);
System.out.printf("canvas %dx%d%n", layout.canvasW(), layout.canvasH());
for (int i = 0; i < layout.placements().size(); i++) {
Placement p = layout.placements().get(i);
System.out.printf("image %d: (%d, %d) %dx%d scale=%.4f%n",
i, p.x(), p.y(), p.w(), p.h(), p.scale());
}
}
}
Also available in 8 other languages
Every CosmoDev tool ships its pure logic in TypeScript (web) and Go (CLI), with authored implementations in a dozen-plus languages — the same contract, ported. Compare all languages side by side →