VisualToPrompt

Image to Prompt as Alt Text: What 480 Lines Actually Say

An image to prompt line is not alternative text. I measured every line this tool writes for forty real image files — 480 lines across four output shapes and three lengths. 408 of 480 (85%) run past a 125-character working cap. 0 of 480 both fit under that cap and name a subject, and 0 of 40 files can produce such a line. The cause is structural: the writer fills its slots with measurements taken from pixels, and the one slot that can name anything fires only on 4 of the 40 files, writing the same four-word phrase in 48 of the 480 lines. Shortening the line removes measured words; it never adds a subject.

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, then pushed through the same analyze → describe → compose path the browser runs. That is 4 shapes × 3 lengths = 12 grids of 40 lines each. I use 125 characters as a working cap for alternative text and report 150 and 200 as sensitivity checks; the cap is a measuring rule for this page, not a standard I am asserting. No model was called, no image was generated and no text from another site was used: every figure below comes from this repository’s source and this machine’s output.

Two conditions, and how the 480 lines meet them

Two conditions decide whether a line could stand in for alternative text: it has to be short, and it has to say what is in the picture. Both are measurable without guessing. Length is simply the character count of the composed line; naming a subject means the writer’s subject slot is non-empty. Here is the whole set first.

The 480 lines as a whole. Percentiles are over character counts; the three cap rows count lines strictly longer than the cap.
MeasureValue
Minimum length90 characters
10th percentile108 characters
25th percentile179.8 characters
Median length216 characters
75th percentile270.3 characters
90th percentile306 characters
Maximum length357 characters
Mean length217.7 characters
Words, minimum / median / maximum14 / 29 / 47
Lines over a 125-character cap408 / 480 (85%)
Lines over a 150-character cap404 / 480 (84.2%)
Lines over a 200-character cap282 / 480 (58.8%)

Raising the cap does not rescue the set. Moving from 125 to 150 characters recovers only 4 lines; even at 200 characters, 282 lines are still over. The median line is 216 characters and 29 words, and the longest is 357 characters. The shortest of all is 90 characters — still 14 words of measurement, not a phrase naming anything.

Broken down by shape and length, only two of the twelve grids ever come in under the cap, and neither does so completely.

Character length by output shape and length; 40 lines in each grid. The last column counts lines at or under 125 characters.
ShapeLengthLinesMinMedianMax≤ 125
Midjourneyshort40157170.52050 / 40
Midjourneymedium402162552980 / 40
Midjourneylong40253300.53400 / 40
Stable Diffusionshort40174187.52220 / 40
Stable Diffusionmedium402332723150 / 40
Stable Diffusionlong40270317.53570 / 40
Fluxshort409710916636 / 40
Fluxmedium401791982600 / 40
Fluxlong40222261.53290 / 40
DALL·Eshort409010214536 / 40
DALL·Emedium401721912390 / 40
DALL·Elong402032222690 / 40

Exactly 0 of the 12 grids has all forty lines under the cap. The 72 short-enough lines are confined to two grids — 36 Flux/short and 36 DALL·E/short. Those two are the sentence shapes at their shortest setting, and they are short because the composer omits contrast, detail and light distribution at that length, not because it has become more concise about the subject.

Now the second condition. The writer sets d.subject in exactly one branch of src/describe.js, when monoRatio > 0.85, and the value it writes is always black and white photograph. On this corpus that happens on 4 of 40 files, producing 48 of 480 lines (10%). The other 36 files have no subject on any of their twelve lines — 432 lines with nothing named. All 48 subject phrases sit inside the first 125 characters of their lines, so trimming cannot even remove the only subject the writer ever produces.

The intersection of the two conditions is empty: 72 lines are short enough, 48 lines name a subject, and 0 of 480 do both. No grid contains one, and 0 of the 40 files can produce one. That is the answer to the question in the title, and it holds at every cap I tried.

Where the characters come from

If the line is too long, the obvious next question is what is filling it. The distribution is not centred near the cap; it is bimodal, with a small pile of very short sentence-shape lines and a large pile of long comma-list lines.

Character-length histogram over all 480 lines. Bands are inclusive of both endpoints.
CharactersLinesShare
0–4900%
50–7400%
75–99153.1%
100–1245711.9%
125–14940.8%
150–174316.5%
175–1999119%
200–2246112.7%
225–2496012.5%
250–29910321.5%
300–3495511.5%
350+30.6%

The single largest band is 250–299 characters with 103 lines (21.5%); only 15 lines (3.1%) fall below 100 characters. There is no band at all between 0 and 74 characters. A line from this tool is, by construction, a string of measurement phrases rather than a short caption.

To separate measured content from packaging, I listed the exact phrases src/compose.js writes for each shape and length, summed their lengths for every line, and called the remainder shell — the commas, sentence frames, quality prefix and ratio parameter that surround the measured values. Payload is therefore a count over real output, and shell is the arithmetic remainder of the real line.

Median payload and shell characters per grid. “Slot phrases” is the median number of measured values the composer writes into a line for that shape and length; shell share is computed per line, then the median is taken.
ShapeLengthSlot phrasesPayloadShellShell share
Midjourneyshort5152.51810.6%
Midjourneymedium8231249.6%
Midjourneylong10273289.4%
Stable Diffusionshort5152.53518.7%
Stable Diffusionmedium82314115.1%
Stable Diffusionlong102734514.2%
Fluxshort3713835.3%
Fluxmedium61544422.4%
Fluxlong8213.54819.5%
DALL·Eshort3713130.8%
DALL·Emedium61543719.6%
DALL·Elong71833917.7%

Shell share runs from 9.4% (Midjourney, long) to 35.3% (Flux, short). In other words, even the most aggressively packaged line is still two-thirds measured adjectives. The comma-list shapes carry a shell of 18 to 45 characters; the two sentence shapes at short length carry 31 and 38 characters around a payload of only 71. Cutting the shell cannot bring a 273-character payload under a 125-character cap.

Those shell characters are not vague padding; they are fixed string literals in src/compose.js, and their lengths are constants.

Fixed shell literals read out of the composer source, with their character counts.
LiteralCharactersWhere it appears
masterpiece, best quality, 27front of every Stable Diffusion line
--ar 6before the ratio on Midjourney lines
dominant palette of 20palette slot on the comma-list shapes
composition12appended to the framing value
, 2glue between comma-list slots
A 2opener on the sentence shapes
image.7first sentence of Flux
The dominant colours are 25Flux colour sentence
with a palette of 18DALL·E palette phrase

What the line says instead of a subject

Alternative text is read by a person who cannot see the image; a line written for a generator is read by a parser. The difference shows up in the characters left in the output. I counted seven markers across all 480 lines, plus the subject facts already established.

Machine syntax and subject presence across the 480 lines. The last four rows restate the subject counts so the two conditions can be compared in one place.
MarkerLines out of 480Share
Carries a --ar parameter12025%
Starts with masterpiece, best quality, 12025%
Ends with a full stop24050%
Starts with A 24050%
Contains a colon480100%
Contains a comma480100%
Contains a digit480100%
Names a subject4810%
Names no subject43290%
Files with a subject4 / 4010%
Files with no subject on any line36 / 4090%
Both short enough and naming a subject00%

The 120 parameter lines are all Midjourney; the 120 quality-tag lines are all Stable Diffusion; the 240 full-stop lines and 240 leading-A lines are Flux and DALL·E. Every one of the 480 lines contains a colon, a comma and a digit — not prose punctuation, but because all forty files are 16:9, so the ratio string 16:9 appears in every line. A reader who cannot see the picture would receive a ratio, an exposure band, a palette and a light distribution, and on 432 of the lines not a single word about what the picture depicts.

This is not a failure of wording. src/describe.js deliberately keeps its scene hint conservative: it comments that guessing “foliage” from a green histogram is exactly the kind of confident wrong answer the library tries not to produce. So the subject slot stays empty unless monochrome is measured, and the four files that do trigger it all receive the same phrase — black and white photograph — on each of their twelve lines. That is a statement about the pixels, not about the content of the photograph.

What trimming to 125 characters takes out

The obvious fix is to cut the line down. I tried two versions. A hard slice at 125 characters leaves 290 of the 408 over-cap lines ending in the middle of a word. Trimming on word boundaries instead — dropping whole words from the tail until the line fits — is cleaner, and here is what it costs.

Word-boundary trimming to 125 characters, measured on all 480 lines. “Out of range” uses this site’s own weight parser band of 0.4–1.6.
MeasureBefore / result
Lines already at or under 125 (unchanged)72 / 480
Words removed, median (min–max)12 (0–31)
Remaining characters, median (min–max)121 (90–125)
Lines losing the --ar tail120 / 480
Lines losing the mood phrase160 / 480
Lines losing the palette label12 / 480
Lines losing the subject phrase0 / 480
Out-of-range lines, before → after120 → 0
Out-of-range terms, before → after120 → 0
Words removed, median: Midjourney / Stable Diffusion18 / 19
Words removed, median: Flux / DALL·E10 / 9

The trimmed line is a different object. It has lost a median of 12 words, up to 31; the 160 lines that carried a mood phrase all lose it, because mood is written last in the long length; the ratio parameter disappears from all 120 Midjourney lines; and the palette label goes from 12 Flux lines. The subject is lost from 0 lines — it sits at the front, and on the other 432 lines there was none to lose. Nothing about the picture has been added.

One side effect is worth naming precisely. This site’s own weight parser flagged 120 lines before trimming and 0 after, because the only out-of-band term in the whole corpus is the Midjourney ratio tail, and trimming deletes it. That is a consequence of deletion, not a repair: the line is shorter, not better formed, and the parser’s silence says nothing about whether the text now describes the image.

Here are the two ends of the real output, verbatim, so the shape of the problem is visible without a summary.

shortest  90 characters / 14 words  [DALL-E / short]
A widescreen 16:9 image, well-lit, balanced exposure, with a palette of tan, brown, olive.

longest  357 characters / 46 words  [Stable Diffusion / long]
masterpiece, best quality, widescreen 16:9 composition, moderate, slightly dim lighting, dominant palette of moss green, charcoal, tan, beige, moderately saturated colour, warm golden colour temperature, medium contrast, highly detailed with intricate texture, light falling on the centre with darker edges, brighter upper half, balanced, natural atmosphere

The 90-character line is the closest this corpus gets to a caption, and it is still a framing ratio, an exposure band and three colour names. The 357-character line is ten measured slots plus a 27-character quality prefix. Neither mentions a person, an object, a place or an action.

Forty files, twelve grids, one 125-character cap

The forty files are the same corpus used elsewhere on this site: 39 stock photographs at 640 × 360 plus one 800 × 450 code screenshot, decoded locally, box-downsampled to 192 × 192, then measured and written by the identical analyze → describe → compose path the browser runs, across four output shapes and three lengths — 480 lines. Every count in this page was produced by one script and is on disk: prep/day46_alt.mjs writes prep/day46-alt.json and prep/day46-alt.log, and the verbatim run is in prep/day46-run.log. Source facts come from src/describe.js (the monoRatio > 0.85 subject branch) and src/compose.js (the four shapes, the three lengths and the fixed literals listed above). A number-by-number check is in prep/day46-number-audit.md.

Three limits on reading these figures. The corpus is 39 landscape photographs and one screenshot, and every one of them is 16:9; a set with other aspect ratios would change the length of individual lines slightly, but not the slot structure or the empty subject slot. The 125-character cap is a working threshold chosen for this measurement, which is why 150 and 200 are reported alongside it — the conclusion holds at all three. And no model was called, no image was generated and no video was produced: every statement here is about the words this tool writes, not about what any generator would do with them.

For the twelve slots the line is built from, see what an image to prompt tool measures. For how the same measurements are worded by each of the four output shapes, see the four lines side by side. For the cut points at which each phrase flips, see the cut-point table; for the closed vocabulary behind those phrases, see what the describer actually writes, and for the ratio parameter that ends up in the parser, see weighting a prompt and writing a negative.