VisualToPrompt

Image to Prompt Stability: Same Bytes, Different Exports

Two answers, and the difference is what you mean by "the same picture". Hand the tool the identical bytes and it does not wobble: forty files × twelve lines × nineteen repeat runs is 9,120 line comparisons, and 0 of them came back different; the eight measurements this page tracks were bit-identical on all 760 repeat comparisons. Re-export that picture and the guarantee is gone. At six bits per channel, 214 of 480 lines change. At 80 pixels wide, 338 do. Adding or subtracting one from every colour channel of every pixel — a change no eye can see — moves 80. The tool is deterministic; the file you hand it is not, and that is where every difference on this page comes from.

What these numbers are. Forty real files — 39 photographs at 640 × 360 and one code screenshot at 800 × 450 — decoded on this machine, box-downsampled to the 192 × 192 grid the live tool measures on, and composed into four shapes at three lengths: 480 lines. A “difference” is one character or more between two composed strings. Every figure below comes from re-running that pipeline on rebuilt files, not from a description of it. No image generator was run and no image was generated — there is no image model behind this site and none was called — so all of this is about the words the tool writes about a file, never about what any model would draw.

Twenty runs on the same bytes

The first question is the narrow one: if nothing about the file changes, does anything about the output change? Each of the forty files was put through the complete pipeline — decode, downsample, measure, classify, compose — twenty times over, and each run’s twelve lines were compared character-for-character against the first run’s.

Four checks on the same forty files. “Comparisons” is the number of pairs actually compared; “different” is how many of those pairs disagreed.
What was held fixed, and what was repeatedComparisonsDifferent
Identical file bytes, full pipeline, 20 runs — all 12 lines compared9,1200
The eight measurements behind the words, 20 runs, compared bit-for-bit7600
The palette array, 20 runs, compared as a whole array7600
The batch of 40 files processed in three orders (original, reversed, shuffled)9600

Two things are worth pulling out of that. The first is that “0” is not a rounding artefact: the eight measurements were compared as exact JSON strings, so a difference in the tenth decimal place would have counted, and none appeared. The second is that the one thing that did move is time — a single file through the whole pipeline took a median of 19.10 ms across 800 runs, ranging from 14.01 to 40.13 ms, which is scheduling noise on this machine and nothing to do with the output.

The only place a deterministic pipeline could still surprise you is a tie: the palette is sorted by share, and two colours with exactly equal shares would be ordered by whatever the sort does with them. In these forty files that never happens — 0 of 40 have two palette entries with the same share — so the ordering is decided by the numbers every time. Processing order does not matter either: the same forty files were run in their original order, reversed, and in a fixed shuffled order, and 0 of 960 lines moved. There is no state carried from one file to the next.

Eleven ways to write the same PNG

Now hold the pixels and change the container. Each file was decoded, re-encoded from its own pixels into eleven different PNGs — every one of the five scanline filter types, two deflate levels, a timestamped text chunk, colour-management chunks, the image data split across eight chunks, and an RGBA colour type with a full alpha channel — then decoded again and run through the whole pipeline.

Eleven container variants of the same forty pictures. “Median file size” is across the 40 files; the original files have a median size of 243,038 bytes. “Pixels match” is how many of the 40 decoded back to exactly the pixels they were encoded from.
PNG variantMedian file sizeLines changedPixels match
filter 0 (none)374,8360 / 48040 / 40
filter 1 (sub)274,2270 / 48040 / 40
filter 2 (up)273,3510 / 48040 / 40
filter 3 (average)275,8760 / 48040 / 40
filter 4 (paeth)263,4440 / 48040 / 40
deflate level 0 (stored)701,4520 / 48040 / 40
deflate level 9374,4380 / 48040 / 40
plus a tEXt export timestamp374,8850 / 48040 / 40
plus gAMA and sRGB chunks374,8650 / 48040 / 40
image data split across 8 chunks374,9200 / 48040 / 40
colour type 6 (RGBA)381,6640 / 48040 / 40

5,280 line comparisons, no difference in any of them, and all 440 re-encodes decoded back to the exact pixels they started from. The size column is there to show the container really did change: the same pixels stored uncompressed take a median of 701,452 bytes against 374,438 at the highest deflate level, a median gap of 314,347 bytes, and the timestamp chunk adds exactly 49 bytes. None of it reaches the words. Whatever your exporter writes into the file — when you exported it, what profile it tagged, how it packed the rows — is discarded before a single measurement is taken.

How far the colour can be cut before the words move

Container changes are invisible because the pixels survive them. The next question is where the words actually give: keep everything else and reduce the colour depth, one bit per channel at a time, eight bits down to one.

Colour depth per channel, from the original 8 bits down to 1. “Lines changed” is out of 480; “files affected” is out of 40. “Max brightness drift” is the largest move in meanL (0–255) across the 40 files at that depth.
BitsLevelsLines changedFiles affectedMax brightness drift
82560 / 4800 / 400.000
712857 / 4806 / 400.648
664214 / 48020 / 401.886
532276 / 48026 / 404.820
416407 / 48037 / 4011.876
38458 / 48039 / 4025.095
24480 / 48040 / 4040.968
12480 / 48040 / 4089.402

Per file, the first depth at which any of its twelve lines moves is a median of 6 bits: sixteen files first move there, eight at five bits, seven at four, six at seven, and three at three. Nothing in this set survives below three bits. The mechanism is not exotic — quantising brightness by up to 89.402 grey levels pushes it across the cut points that decide the exposure and mood phrases, and quantising colour pushes saturation across the ones that decide vivid against moderately saturated. The words are thresholds, so a change only matters when it lands on one.

What that looks like on a single file, at the long Midjourney line. Six bits and four bits leave it untouched; two bits rewrites three separate clauses at once — a fourth colour appears, saturation flips from moderate to vivid, and the mood drops from uplifting to neutral:

baseline  widescreen 16:9 composition, well-lit, balanced exposure, dominant palette of tan, brown, olive, moderately saturated colour, warm golden colour temperature, medium contrast, moderate detail and texture, evenly lit, brighter upper half, bright and uplifting atmosphere --ar 16:9
6 bit     unchanged
4 bit     unchanged
2 bit     widescreen 16:9 composition, well-lit, balanced exposure, dominant palette of tan, charcoal, olive, brown, vivid, saturated colour, warm golden colour temperature, medium contrast, moderate detail and texture, evenly lit, brighter upper half, balanced, natural atmosphere --ar 16:9

How small the re-export can be

The other thing an exporter does is change the size. Each file was resampled down to a given width — height scaled to keep the ratio — and then measured on the same 192 × 192 grid, so the only variable is how many of the original pixels were left to average into each cell.

Width the file was re-exported at, from the original 640 (or 800) down to 10 pixels. “Max edge drift” is the largest move in the edge-density measurement across the 40 files; it is the measurement that reacts first and hardest.
WidthLines changedFiles affectedMax edge driftRatio the tool writes
640 px0 / 4800 / 400.01716:9
512 px176 / 48016 / 400.77516:9
320 px129 / 48012 / 400.65116:9
160 px188 / 48018 / 409.75016:9
80 px338 / 48031 / 4032.39216:9
40 px459 / 48040 / 4054.16040:23
20 px462 / 48040 / 4063.42420:11
10 px480 / 48040 / 4064.6885:3

Every one of the forty files first moves somewhere between 512 and 40 pixels wide, with a median of 240 px: sixteen first move at 512, eleven at 80, five at 40, four at 320 and four at 160. Note that the count is not monotone — 320 px changes fewer lines than 512 px does — because moving a value away from a threshold and then back across it is not the same as never crossing it. The measurement that drives most of this is edge density: at 80 px it has moved by up to 32.392, on a scale where the whole corpus runs from 3.71 to 65.84. Brightness barely budges at any width (at most 0.619), because averaging pixels preserves their average.

The last column is the one to watch. Down to 80 px the ratio the tool writes is still 16:9, but at 40 px every file in the set — 40 of 40 — starts reporting 40:23, then 20:11, then 5:3. Nothing about the picture changed shape; the height was rounded to a whole number of pixels, the ratio stopped reducing to 16:9, and the tool reported the numbers it was given. A thumbnail of a 16:9 photograph is not always 16:9, and the tool will tell you what the file says rather than what you meant.

The nudge that does nothing, and the one that does

So the words hold across a re-encode and give way on a re-export. The finest version of the question is: what is the smallest change to the pixels that still moves a line? Four perturbations, applied to the full-resolution pixels of all forty files before any measurement.

Four perturbations at the pixel level. “Max brightness drift” is the largest move in meanL across the 40 files.
PerturbationLines changedFiles affectedMax brightness drift
One pixel in the centre, red +10 / 4800 / 400.0000058
Every pixel, every colour channel ±1 (fixed pseudo-random)80 / 4808 / 400.0354
Every pixel, all three channels +1144 / 48012 / 401.0041
Chroma subsampled 4:2:0 (2 × 2 blocks averaged)36 / 4803 / 400.0242

The first row is the floor. One pixel out of 230,400 was brightened by one step and 0 of 480 lines moved; brightness shifted by 0.0000058 grey levels, and the largest move in any of the eight measurements tracked here was 0.0000271. That is what a single pixel is worth after the resize averages 6.25 of them into each cell and 36,864 cells are averaged again.

The second and third rows are the ones that matter in practice, and they are not the same size of change. Shuffling every channel of every pixel by one step either way — visually identical, and it moves brightness by at most 0.0354 — still changed 80 lines on 8 files. Pushing every channel up by one, which is exactly +1 grey level under the Rec.709 weights the tool uses for brightness and measured 1.0041, changed 144 lines on 12 files. Both are changes no one can see, and both are large enough to cross a threshold on a fifth to a third of the corpus — which is the honest statement about stability: the tool will always give you the same answer for the same bytes, and the set of pictures that produce your line is far narrower than you would guess from how coarse the vocabulary is.

Chroma subsampling is the gentlest of the four and the most instructive about which measurements are fragile. It moved 36 lines on 3 files, and it did so evenly: three files, twelve lines each, every shape and length affected identically. Saturation moved by at most 0.0062 and warmth by at most 0.128. Averaging colour in 2 × 2 blocks is what most photo formats do by default, and on this corpus it is the one re-export that usually leaves the words alone.

What the 9,120 repeat runs and 1,240 rebuilt files were run on

Forty files, twelve lines each: 480 baselines. The repeat test re-ran the full pipeline twenty times per file (800 runs, 9,120 line comparisons, 760 measurement comparisons, 760 palette comparisons) and once more in two alternative batch orders (960 comparisons). The container test rebuilt each file eleven ways from its own pixels: 440 re-encodes, 5,280 line comparisons, and a pixel-by-pixel check that all 440 decoded to exactly what was encoded. The re-export tests rebuilt each file at eight colour depths, eight widths, one chroma subsampling and three noise patterns: 800 rebuilt files with altered pixels and 9,600 further line comparisons. “Changed” means a difference of one character or more against that file’s own baseline; no comparison is against another file.

Three limits belong next to these numbers. The re-exports are simulations of what an exporter does — quantisation, resampling, chroma averaging — not real JPEG or WebP files, so they establish how much a change of that kind has to be worth before the words move, not what any specific program produces. The corpus is forty stock photographs plus one screenshot, all 16:9, so the ratio column is a statement about files that start at 16:9 and the depth thresholds are the ones this set lands near; a set of near-duplicate images would move sooner. And no generator was run: nothing here says what any image model would draw from these lines, only which lines this tool writes about which files.

What survives all three caveats is the split the numbers show. Determinism is a property of the file, and it is absolute: same bytes, same twelve lines, every time, whatever the container says, whatever order the batch ran in. Robustness is a property of the picture, and it is thin: six bits of colour, a fifth of the original width, or one grey level added everywhere is enough to rewrite part of the line. If you are checking a tool, run the same file twice — that is the check on how to test an image to prompt site. If you are keeping a line, keep the file it came from, because that is the only thing the words are actually a statement about.

For the twelve measurements the words are read off, see what an image to prompt tool measures; for the resize that turns your pixels into the 36,864 cells every measurement is taken on, where your image goes; for the cut points each phrase flips at, the twenty-nine cut points; and for how far a picture can be pushed while every line stays identical, how far the round trip gets you.