KRA to PNG API
POST a Krita .kra file to /v2/convert/kra/to/png and get one PNG back as base64 in the JSON. Our converter rebuilds the picture from the paint layers themselves, so opacity, groups, transparency masks and most blend modes apply, and a transparent canvas stays transparent.
- Endpoint
- POST /v2/
convert/ kra/ to/ png - Accepts
- kra
- Sample timing
- 23 ms median of 5 runsHow we measure
- Request size
- Up to 10 MB on the Free plan or 100 MB on paid plans, all files together
Request and response
Every sample below ran against the API before this page was published. Set PDFCONVERSIONAPI_KEY to your key and run it as is.
curl -sS -X POST \
https://api.pdfconversionapi.com/v2/convert/kra/to/png \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@rocket-sticker.kra \
-o response.json
# FileData is base64. Save the first file in converted/,
# or print the JSON error.
if jq -e '.Files' response.json > /dev/null; then
mkdir -p converted
name=$(jq -r '.Files[0].FileName' response.json)
jq -r '.Files[0].FileData' response.json \
| base64 --decode > "converted/$name"
else
cat response.json
fiimport base64
import os
import requests
key = os.environ["PDFCONVERSIONAPI_KEY"]
response = requests.post(
"https://api.pdfconversionapi.com/v2/convert/kra/to/png",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("rocket-sticker.kra", "rb"))],
timeout=180,
)
result = response.json()
if not response.ok:
raise SystemExit(f"{result['Code']}: {result['Message']}")
os.makedirs("converted", exist_ok=True)
for file in result["Files"]:
path = os.path.join("converted", file["FileName"])
with open(path, "wb") as out:
out.write(base64.b64decode(file["FileData"]))
print(path, file["FileSize"], "bytes")
import { mkdir, readFile, writeFile } from "node:fs/promises";
import { join } from "node:path";
const form = new FormData();
const file = "rocket-sticker.kra";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/kra/to/png";
const key = process.env.PDFCONVERSIONAPI_KEY;
const response = await fetch(url, {
method: "POST",
headers: { Authorization: `Bearer ${key}` },
body: form,
});
const result = await response.json();
if (!response.ok) {
throw new Error(`${result.Code}: ${result.Message}`);
}
await mkdir("converted", { recursive: true });
for (const file of result.Files) {
const path = join("converted", file.FileName);
await writeFile(path, Buffer.from(file.FileData, "base64"));
console.log(path, file.FileSize, "bytes");
}
{
"ConversionCost": 1,
"ConversionTime": 0.023,
"Files": [
{
"FileName": "rocket-sticker.png",
"FileExt": "png",
"FileSize": 27925,
"FileData": "iVBORw0KGgoAAAANSUhEUgAA…"
}
]
}Response from our test run on 2026-11-03. ConversionTime shows the median of 5 runs. FileData is shortened here; the real response carries the whole file as base64.
The sample, converted
The same file the code sends. Download the input and the output and compare them yourself.

- Input
- rocket-sticker.kra (108 KB)
- Output
- rocket-sticker.png (27 KB)
- Source
- A cartoon rocket sticker on a transparent canvas that we drew and saved as a six-layer KRA file (one layer hidden, one faded by a transparency mask). (CC0-1.0). How it was made
- Made by
- 2026-11-04, API build
9eeeb0640aba
Parameters
Send these as form fields next to the file. Names are case-insensitive. If you set one of the documented options below that we don't support yet, the request fails with a 400 that names it instead of returning a file made without it.
| Parameter | What it does |
|---|---|
ImageWidthinteger | Width of the PNG in pixels; the height follows the canvas. ImageWidth=1280 turned the 320 × 320 rocket into a 1280 × 1280 PNG of 342,915 bytes. Scaling happens after the layers are merged.Values: 1–20000 |
ImageHeightinteger | Height in pixels. Sent together with ImageWidth, the two form a box: 200 × 100 gave a 100 × 100 PNG, because the sticker's canvas is square.Values: 1–20000 |
ScaleProportionsboolean, default true | false fills the ImageWidth × ImageHeight box exactly. The same 200 × 100 request then returned a squashed 200 × 100 rocket of 10,898 bytes. |
ScaleIfLargerboolean, default false | true allows shrinking only. Paired with ImageWidth=800, it handed back the 320 px PNG unchanged, byte for byte. |
ScaleImageboolean, default true | false crops from the top-left corner instead of scaling. A 120 × 90 crop of the sticker is entirely transparent canvas. |
ColorSpaceenum, default default | gray writes a gray PNG that still carries alpha (14,821 bytes); monochrome snaps each pixel to black or white at level 128 and also keeps alpha (8,168 bytes). truecolors gives what leaving the option out gives, while rgb turns gray into color: a 64 × 48 gray test file came back as a 298-byte gray PNG by default and as a 389-byte RGB PNG with rgb.Values: default (also truecolors), rgb (also srgb), gray (also grayscale), monochrome; cmyk returns 400 |
ImageResolutioninteger | Adds a pHYs chunk with this DPI. The KRA declares 300 ppi, yet the PNG records none until you send ImageResolution=300, which adds 21 bytes.Values: 10–800 |
TransparentColorstring | Pixels of exactly this color turn fully transparent. #FFFFFF cleared 104 pure white pixels on top of the 83,159 empty canvas pixels: faint edge pixels of the rocket body, 102 of them already partly clear. The highlights blend with the body below, are not pure white and stay.Values: #RRGGBB, R,G,B or white, black, red, green, blue, gray |
FileNamestring | Base name for the result. Without it, rocket-sticker.kra returns as rocket-sticker.png. |
StoreFileboolean, default false | true keeps the PNG on our side for 3 hours; the JSON then holds a Files[].Url link where FileData would be. |
What carries over, and what doesn't
Kept
- The merged look of the visible layers: our own composite of the six sample layers matched the PNG within 1 level on all 102,400 pixels
- Alpha, as an RGBA PNG: 83,159 fully transparent and 4,962 partly transparent pixels in the sample
- Layer opacity (the 35% shadow, the 70% highlights), the window layer's offset to 162, 92 and the transparency mask that fades the flame
- Groups, pass-through groups included, and blend modes such as Multiply, Screen, Overlay, Color Dodge, Soft Light and Luminosity
- 16 bits per channel from 16-bit integer RGBA and grayscale canvases; an 8-bit gray canvas gives a gray PNG
Lost or not yet supported
- Layers. The PNG is flat: the layer names, the hidden sketch and the mask itself are gone.
- Vector layers, which hold text and shapes from Krita's vector tools, along with filter, fill, clone and file layers. They are dropped without an error.
- A few blend modes, such as Linear Light, Hard Mix, Erase and Behind, which are drawn as Normal.
- The 300 ppi stored in the file and any embedded color profile. The PNG has only IHDR, IDAT and IEND chunks.
- Live merging for float, CMYK and Lab canvases: those return the flattened copy Krita saved in the file, and fail with 422 when it is missing.
Limits
- One .kra per request, with a canvas of at most 100,000,000 pixels and 300,000 px a side: 10,000 × 10,000 worked, 10,001 × 10,000 returned 413 and 300,001 × 1 returned 422.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- 120 seconds per conversion, then 504.
- Resize targets from 1 to 20,000 px per side.
- Our test files come from our own KRA writer. Files saved by Krita itself, and animated documents, are not tested yet.
Where teams use it
Previews of Krita masters
Comic, game and illustration teams that keep .kra files in a repository or an asset manager can render a PNG whenever a file changes, so reviewers see the artwork in a browser without installing Krita.
Stickers and overlays with soft edges
Artwork painted on a transparent canvas keeps its anti-aliased edges and its soft shadow: the sample's 4,962 partly transparent pixels arrive with their alpha, ready for a cut-line step or a web overlay.
16-bit paintings into an image pipeline
A canvas in Krita's 16-bit integer RGBA mode comes back as a 16-bit PNG, so painted gradients keep their extra precision for the next processing step.
Questions
Is the PNG just the merged image Krita stores inside the .kra?
No, not for 8-bit or 16-bit RGB and grayscale files. We swapped the sample's stored merged image for solid red and still got the same PNG, byte for byte, because the layers are merged again from their own pixel data. The stored copy is only used for float, CMYK and Lab canvases, which we can't merge yet.
Why is the text from my drawing missing?
Text and shapes made with Krita's text and vector tools sit on vector layers, and those are not rendered yet. The request still returns 200, so check for this before you rely on the output. Turning those layers into paint layers in Krita before saving makes them appear.
Are hidden layers included?
No. The sample's top layer is a red sketch switched off in the file, and not one opaque pure red pixel reaches the PNG. A hidden group is skipped together with everything inside it.
Can I get each layer as its own PNG?
Not today. The route returns one merged PNG per request and has no option to pick a layer. Hide the layers you don't want before saving, or split them into separate files first.
Convert your first KRA file in a minute.