Code to Image Screenshot Maker

Turn a code snippet into a polished, shareable PNG screenshot with syntax highlighting and window chrome. Runs entirely in your browser; nothing is uploaded.

🌐 Español

🔒 Private by design: your text is processed locally in your browser and never uploaded to any server.

Auto-detect, and when to override it

Highlighting is done by highlight.js, running as JavaScript in your tab. Nineteen grammar modules are wired up, each loaded on demand, eighteen real languages plus plain text, and the dropdown shows 22 entries because JSX and TSX map onto the JavaScript and TypeScript grammars and HTML maps onto XML. A language name that is not on the list falls back to Auto-detect rather than erroring.

Leave the selector on Auto-detect and highlight.js scores your snippet against all nineteen grammars and keeps the winner. That works well for anything with a distinctive shape: a Python def block, an HTML tag soup, a shell command with flags. It works much less well for short or ambiguous input, and the reason is structural rather than a bug. A three line JSON object is also valid Python, and a SQL SELECT in lower case looks a lot like plain prose. Five lines simply do not carry enough signal for confidence scoring to be reliable.

So the practical rule is: leave it on auto for anything over about ten lines, and set the language explicitly for a short fragment. Naming the language skips detection and loads only that one grammar, which is also marginally faster.

Theme, background, and what survives being projected

Five themes ship: Dracula, GitHub Dark, Nord, Monokai and One Light. Rather than bundling highlight.js’s own theme CSS, each is a hand written map of token colours, which is why all five cover exactly the same token classes and none has a comment colour that silently falls back to the default foreground.

Choosing between them is mostly about where the image is going. Dracula and Monokai are high-saturation dark themes that look great on a screen and can lose their pink and green keywords on a washed-out projector. Nord is the lowest contrast of the five and the safest for print. One Light is the only light option and the right pick for a white slide deck, because a dark code block on a white page pulls the reader’s eye away from everything around it.

Backgrounds are separate from themes: three gradients (purple, blue, orange), a solid dark, or transparent. The gradients exist because a code frame floating on flat white looks unfinished on social media. If you are compositing the frame into your own design, choose transparent and let your layout provide the backdrop.

From pasted snippet to PNG

  1. Paste your code into the box. Indentation is preserved verbatim, and tabs render as two spaces.
  2. Set the Language (or leave Auto-detect), a Color theme and a Background.
  3. Toggle the window title bar and set the frame padding anywhere from 0 to 128 pixels.
  4. Generate, then download code-screenshot.png.

Padding is the outer breathing room between the code window and the edge of the image, drawn in the background colour or gradient. The default 48 is a good social-media value; drop it to 0 when you plan to place the frame inside a layout that already has its own margins.

Escaping, sandboxing, and code you are not allowed to leak

A tool that turns arbitrary pasted text into HTML and renders it is an obvious injection target, so this one has two independent defences and we verified the first one against the real library instead of trusting the documentation.

highlight.js escapes as it tokenises: every <, >, & and " in your input comes back as an HTML entity, for every grammar, including the case where the code genuinely is HTML and you picked the html language on purpose. The test suite fires real payloads (a <script> tag, an <img onerror>, an attempt to break out of the surrounding </code></pre>) through the unmocked library for several languages and asserts the escaping every time.

On top of that, the assembled document is rendered inside a sandboxed iframe with scripting disabled before the capture runs. Even a future bug in this tool’s own template building, say a caption field added later without escaping, could not execute anything. And because both stages are local, your snippet never crosses the network: highlighting is a function call, and the capture reads a hidden frame in your own tab. That is the part that matters when the code comes from a private repo or an unreleased feature.

The dynamic import that only broke in a real browser

Worth recording, because it is a trap. The natural way to load nineteen grammars on demand is one interpolated import: build the path from the language name and call import() on it. That version passed every Node test, because Node’s resolver has no difficulty with a specifier assembled at runtime.

In a real browser it failed outright. Vite can only rewrite a dynamic import into a resolvable URL when the specifier is a static string it can analyse at build time, so the interpolated version shipped as a bare specifier that the browser’s own module resolver rejected with a “Failed to resolve module specifier” error. We caught it by driving the dev server with a real browser rather than by reading the built output. The fix is the tedious thing the file does now: nineteen explicit import statements in a lookup table. That is also why the language list is curated rather than “everything highlight.js can do”, since every grammar has to be named in code.

Where this tool stops

There are no line numbers, no line highlighting, no diff colouring, no filename in the title bar and no font choice; the code is set at 14 pixels in your system monospace stack. Long lines are never wrapped, since wrapping code changes its meaning, so a 300 character line produces a very wide image. The offscreen staging frame is 4000 pixels across, generous but not infinite, and the fix is to break the line yourself before pasting.

If a code frame is not what you need, a few siblings cover adjacent jobs: Markdown to HTML if you want real copyable code on a page instead of a picture, Diff Text for showing what changed between two versions, OG Image Generator for a social preview card with a headline rather than a snippet, and Device Mockup Generator to put a whole screenshot inside a phone or laptop frame.

See it in action

Screenshot of the Code to Image Screenshot Maker tool with the sample input “export async function process(files, options, on…”, Language set to Auto-detect (default), Color theme set to Dracula (default)
Code to Image Screenshot Maker mid-process: the sample input “export async function process(files, options, on…”, Language set to Auto-detect (default), Color theme set to Dracula (default).
Screenshot of the Code to Image Screenshot Maker result screen showing code-screenshot.png ready to download (227 KB)
The finished result: code-screenshot.png ready to download (227 KB). The download link is a local blob URL — the file never leaves your device.

Frequently asked questions

Which languages are actually supported?

Eighteen highlight.js grammars plus a plain-text mode, nineteen loadable modules in all, exposed as 22 dropdown entries because JSX and TSX are aliases of the JavaScript and TypeScript grammars and HTML is an alias of XML. The list covers JavaScript, TypeScript, Python, HTML, CSS, JSON, Bash, SQL, Go, Rust, Java, C#, C++, C, PHP, Ruby, YAML and Markdown. A value that is not on the list is treated as Auto-detect rather than failing.

Auto-detect picked the wrong language. Why?

Auto-detect scores your snippet against all nineteen grammars and takes the highest confidence, which is genuinely hard for short or ambiguous input. Three lines of JSON are valid Python dict syntax; a bare list of words is plausible in half a dozen grammars. If the colouring looks off, set the language explicitly, which skips detection entirely.

What resolution is the PNG, and can I set a fixed width?

The image auto-sizes to your code and is captured at 2x device scale, so a frame measuring 700 by 400 CSS pixels saves as a 1400 by 800 PNG. There is no width setting; the frame is as wide as your longest line plus the code block's own 24 pixels of side padding plus your chosen frame padding. Manually wrapping a long line is the way to make a narrower image.

Why is there no line-number option?

Line numbers, line highlighting and a filename in the title bar are all real requests and none of them are implemented. The title bar is purely decorative, three coloured dots and nothing else. Line numbers in particular are usually noise in a shared screenshot, since the numbers rarely match the reader's file anyway.

Does the transparent background give a genuinely transparent PNG?

Yes. The renderer is told not to fill any background of its own, so the outer padding area keeps a real alpha channel instead of being flattened to white or black. The code block itself stays opaque in its theme colour, which is what you want when dropping the frame onto a coloured slide.

Is it safe to paste code from a private repository?

The code never leaves the tab. Highlighting runs as JavaScript in your browser and the capture happens against a hidden local frame, so there is no request carrying your snippet anywhere. Do check the snippet itself for secrets before you publish the image, since an API key in a screenshot is just as leaked as one in a paste.

Related tools