Bhinish Dhiman
How to make a code screenshot people can actually read
Paste the code into a code-to-image tool, pick a theme, and check its colours against their background before exporting: most syntax themes set comments under 4.5:1. Lift the failing colours with their hue kept, export an SVG with real text for slides or a PNG at 2× for screens, and post the alt text and the code as text alongside the image.
An image of code is everywhere: conference slides, launch posts, documentation, a pull request summary on a social feed. It is also the least accessible way to share code there is. The colours are chosen to look good in an editor, not to be read on a projector, the export is often a blurry screenshot of a web page, and the code inside is invisible to anyone using a screen reader. Each of those has a fix you can apply in a minute.
Make the image with the tool
- Open Code to image. It starts on a sample, a TypeScript contrast function in Dracula, so there is something to measure before you paste anything. TypeScript: contrast ratio, Python: read a CSV and A diff: fix a contrast bug switch between the samples.
- Paste your code into Your code, or press Open a code file (or drop one on the page), which also sets the language from the file’s extension and puts its name in the window bar. When it can tell, the tool guesses the language of pasted code and says so under the box; change Language if it is wrong. Once you choose a language yourself, nothing is guessed again.
- Choose a Theme. Seventeen are offered, eleven dark and six light, all MIT-licensed.
- Read the Contrast panel. It lists every colour under 4.5:1 with the code it colours, the ratio, and the colour it would be lifted to. Leave Accessible colours: lift anything under 4.5:1, keeping its hue ticked to export the lifted colours, or untick it to keep the theme exactly as written.
- Under Frame and type, set the Font, Size, Background, Padding and Window (Dots, Bar or None), and the File name in the bar. Highlight lines takes numbers and ranges such as 3, 5-7. More options holds Line numbers, Diff: leading + and − as markers, which moves those characters into the gutter, Canvas, which fits the card to a fixed size such as Link preview 1200 × 630, and whether the font is embedded in the SVG; its summary line says how each is set.
- Pick a PNG scale of 1×, 2× or 3×, the last setting in Frame and type. The Export panel shows the pixel size, the file size in bytes and the ppi written into the file before you download anything. Press Download PNG, which is also on the bar at the bottom of the screen (D), or Download SVG. Copy link copies the whole image as a link, and Copy image appears where the browser can put a picture on the clipboard.
- Under Alt text and the code as text, press Copy alt text and paste it into the post’s image description, then Copy code or Copy as Markdown and put the code in the post itself.
Syntax themes fail contrast more often than not
Contrast ratio is the WCAG 2 measure of how far apart two colours are in luminance, from 1:1 for identical colours to 21:1 for black on white. Body text needs 4.5:1 to meet level AA. A code image is body text at its smallest: a slide seen from the back of a room, or a post on a phone in daylight.
Measured across the 65 themes that ship with the shiki highlighter, on samples in six languages, 56 themes have at least one token colour under 4.5:1 on their own background, and 49 fail on the comment colour. Comments are dimmed on purpose, so the code stands out in an editor. In an image, the dimmed line is often the one carrying the explanation.
| Theme | Comment colour | On its background | Lifted, same hue |
|---|---|---|---|
| Dracula | #6272a4 | 3.03:1 | #7e90c3, 4.52:1 |
| Nord | #616e88 | 2.43:1 | #8e9cb7, 4.51:1 |
| One Dark Pro | #7f848e | 3.73:1 | #8d939d, 4.53:1 |
| Solarized Light | #93a1a1 | 2.48:1 | #667474, 4.51:1 |
| GitHub Dark (default) | #8b949e | 6.15:1 | No change needed |
The lift moves lightness only, in OKLCH, holding the hue and as much of the saturation as the screen can show, so a blue-grey comment stays a blue-grey comment. The same search runs in the contrast checker for a single pair of colours.
Highlighting a line can break a colour that passed
A highlighted line has its own tint, and the text on it is measured against that tint, not against the theme background. In Dracula, the purple #bd93f9 and the pink #ff79c6 both pass on the plain background, then drop to 4.34:1 and 4.39:1 on a highlighted line, because the tint is lighter than what was behind them. The tool measures each line on its own surface and lifts those two colours on that line only.
Translucent colours have the same problem in another form. Fourteen of the 65 themes use colours with an alpha channel; Vitesse Dark writes its comments as #758575 at 87% opacity. What reaches the screen is that colour blended with the background, and measuring the colour as written overstates its contrast. The tool blends first and measures what is shown.
Why the export format matters
Most code-image sites make their image by photographing their own web page with a library such as dom-to-image or html-to-image. Their SVG export wraps the page’s HTML in a <foreignObject> element, which browsers draw and Figma, Inkscape, Google Slides and PowerPoint show as a blank box. Their PNG is a screenshot, so it inherits the page’s layout bugs, and its sharpness depends on a pixel ratio that some tools take from your screen.
| What you need | Use | Why |
|---|---|---|
| A slide or a document | SVG | Real text, sharp at any size, selectable and searchable; the font is embedded so it looks the same everywhere |
| A post on a social feed | PNG at 2× | Feeds take raster images; 2× stays sharp on high-density phones |
| A printed handout | PNG at 3×, or the SVG | 3× is written as 288 ppi, so it places at its intended size |
| Sharing the editable original | Copy link | The code travels after the #, which is never sent to a server |
The sample image is 9,571 bytes as an SVG, or 37,933 bytes with JetBrains Mono embedded. Embed the font in the SVG, so it looks the same on any machine controls that; without it, the file names the font and the reader’s machine supplies it or falls back to its own monospace. A PNG always has the font inside, because an SVG drawn as an image cannot load a font from anywhere else, which is the same rule that trips up SVG to PNG conversions.
Alt text for code
An image of code cannot be read aloud, searched, copied or translated. Alt text is the description a screen reader speaks in place of an image, and for code the useful description is the code. The tool writes it in the form accessibility writers recommend: the language and line count, then the code itself. When that would pass X’s 1,000-character limit for image descriptions, it writes a summary instead, naming what the snippet declares, and says the full code is in the post. Bluesky allows 2,000 characters. The count shown is in characters as the platforms count them, so an emoji with a skin tone counts as two, not four.
Alt text is a fallback, not a substitute. Post the code as text as well, in the post or in a linked gist, so people can copy it.
Other ways to do it
A screenshot of your own editor is a raster at your screen’s pixel density, with the editor’s own theme colours and no alt text; on a 1× monitor it will look soft on a phone. Editor extensions that make code images work the same way as the websites, through a picture of a web view: in their source, CodeSnap for VS Code exports at a fixed 2× and Polacode has no scale setting at all.
Check that nothing was uploaded
Open your browser’s developer tools, go to the Network tab, and make an image. The tool’s only requests are for the highlighter, the theme and grammar you chose, and the font, all from this site; the page’s one analytics beacon is described on the privacy page, and your code is in none of them. A shared link keeps the code after the #, which the browser never sends to a server.
Make one now with Code to image, or check a single colour pair with the contrast checker.