KRA to PNM API
/v2/convert/kra/to/pnm returns the merged Krita layers as uncompressed 8-bit RGB in a Netpbm file. Since the output has no alpha, the transparent canvas is blended onto white by default. The file is a binary PPM (P6), or a PGM (P5) when you ask for gray or monochrome.
- Endpoint
- POST /v2/
convert/ kra/ to/ pnm - 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/pnm \
-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/pnm",
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/pnm";
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.pnm",
"FileExt": "pnm",
"FileSize": 307215,
"FileData": "UDYKMzIwIDMyMCAyNTUK////…"
}
]
}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.pnm (300 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 |
|---|---|
AlphaColorstring, default white | What the empty canvas and soft edges are blended onto. With #1B1F3B the first pixel of the file reads 27, 31, 59 instead of 255, 255, 255.Values: white, black, red, green, blue, gray, #RRGGBB or R,G,B |
BackgroundColorstring, default white | Fallback name for the same backdrop, read only when AlphaColor is absent.Values: Same as AlphaColor |
ImageWidthinteger | Width in pixels. File size is predictable: the header plus 3 bytes per pixel. The header is 15 bytes when both sides have three digits, so 128 px gives 49,167 bytes; at 64 px it shrinks to 13 bytes and the file is 12,301.Values: 1–20000 |
ImageHeightinteger | Height in pixels; with a width it defines a box the square canvas fits into.Values: 1–20000 |
ScaleProportionsboolean, default true | false fills a 200 × 100 box completely (60,015 bytes) instead of giving 100 × 100. |
ScaleIfLargerboolean, default false | true turns any enlargement into a no-op. |
ScaleImageboolean, default true | false cuts the box out of the top-left corner without resampling. |
ColorSpaceenum, default default | gray and monochrome switch to a one-channel PGM (P5): 102,415 bytes for the sticker, a third of the RGB file. monochrome holds only the values 0 and 255.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
FileNamestring | Base name of the .pnm you get back. |
StoreFileboolean, default false | Puts the file in storage for 3 hours and returns a link. |
What carries over, and what doesn't
Kept
- The merged color of every visible layer, blended onto the chosen backdrop
- Exact 8-bit values: after the 15-byte header come 307,200 bytes, 3 per pixel for 320 × 320
- Soft edges, mixed with the backdrop by their alpha rather than cut off
- Reader support: the P6 sample opened in both readers we tried, with identical pixels
Lost or not yet supported
- Transparency. PNM stores no alpha here, so the 83,159 empty canvas pixels become the backdrop color.
- 16-bit depth: values are written as 8-bit, MAXVAL 255.
- Resolution and color profile, which Netpbm does not store;
ImageResolutionhas no effect. - Text and shapes on Krita vector layers, which are not drawn.
Limits
- One KRA per call, canvas up to 100,000,000 pixels and 300,000 px wide or tall.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- Stopped with 504 after 120 seconds.
- Binary output only: P6 for color, P5 with
ColorSpace=grayormonochrome. There is no ASCII or PAM variant.
Where teams use it
Input for image-processing code
Research code, test harnesses and command-line tools that read Netpbm can take artwork kept as .kra this way, without a Krita reader in the project: the pixels follow a short plain-text header.
Fixed-size test frames
Because the layout is fixed (15 header bytes, then 3 bytes per pixel for the sample), a test can compare frames byte by byte after a drawing changes.
Questions
Is the output P6 (PPM)?
Yes. The file opens with a 15-byte text header: 'P6' on the first line, then '320 320 255' for width, height and MAXVAL. The 307,200 bytes after it are RGB, 3 per pixel, from the top row down. With ColorSpace=gray the header says P5 and each pixel takes one byte.
What happens to the transparent background of my Krita file?
It is blended onto white, or onto AlphaColor when you send one. Partly transparent pixels mix with that color by their alpha, so the sticker's 35% shadow turns light gray on white.
Are groups and masks applied before the PNM is written?
Yes. The layers are merged first, with groups, opacity, transparency masks and blend modes, and the PNM gets the result. Hidden layers, like the sample's red sketch, are not included.
Convert your first KRA file in a minute.