Photo Merge — C 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 C implementation — the same logic the interactive tool runs, in a shareable, citable form.
/* photo-merge — C (C11) port: side-by-side merge cell layout. */
#include <math.h>
#include <stdio.h>
/* 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. */
typedef struct {
int width, height;
} ImageSize;
/* Where one image lands on the merged canvas. */
typedef struct {
double scale;
int x, y, w, h;
} Placement;
/* Merged canvas dimensions plus one placement per input image.
* 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. JS Math.round
* rounds half up; lround matches that for the positive values here.
* Returns the number of placements written (== n). */
int merge_layout(const ImageSize *images, int n, int gap,
int *canvas_w, int *canvas_h, Placement *out) {
int cell_w = 0, cell_h = 0;
for (int i = 0; i < n; i++) {
if (images[i].width > cell_w) cell_w = images[i].width;
if (images[i].height > cell_h) cell_h = images[i].height;
}
*canvas_w = n * cell_w + (n + 1) * gap;
*canvas_h = cell_h + 2 * gap;
for (int i = 0; i < n; i++) {
double scale = cell_w / (double)images[i].width;
double hscale = cell_h / (double)images[i].height;
if (hscale < scale) scale = hscale;
int w = (int)lround(images[i].width * scale);
int h = (int)lround(images[i].height * scale);
out[i].scale = scale;
out[i].w = w;
out[i].h = h;
out[i].x = gap + i * (cell_w + gap)
+ (int)lround((cell_w - w) / 2.0);
out[i].y = gap + (int)lround((cell_h - h) / 2.0);
}
return n;
}
int main(void) {
/* 800x600 + 600x800 + 1024x768 with a 12px gap -> 3120x824 canvas. */
ImageSize images[3] = {{800, 600}, {600, 800}, {1024, 768}};
Placement placements[3];
int canvas_w, canvas_h;
int n = merge_layout(images, 3, 12, &canvas_w, &canvas_h, placements);
printf("canvas %dx%d\n", canvas_w, canvas_h);
for (int i = 0; i < n; i++) {
printf("image %d: (%d, %d) %dx%d scale=%.4f\n", i,
placements[i].x, placements[i].y,
placements[i].w, placements[i].h, placements[i].scale);
}
return 0;
}
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 →