KRA to BMP API
Call /v2/convert/kra/to/bmp with a .kra file and you get a Windows bitmap of the merged layers. A canvas with transparency, like the sample, gives 32 bits per pixel with a BITMAPV4 header and alpha in the fourth byte; a fully opaque canvas gives a 24-bit bitmap.
- Endpoint
- POST /v2/
convert/ kra/ to/ bmp - Accepts
- kra
- Sample timing
- 24 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/bmp \
-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/bmp",
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/bmp";
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.024,
"Files": [
{
"FileName": "rocket-sticker.bmp",
"FileExt": "bmp",
"FileSize": 409722,
"FileData": "Qk16QAYAAAAAAHoAAABsAAAA…"
}
]
}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.bmp (400 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 bitmap. On the transparent sticker every pixel costs 4 bytes, so 160 px wide gave 102,522 bytes and 800 px gave 2,560,122.Values: 1–20000 |
ImageHeightinteger | Height of the bitmap; ImageHeight=150 alone gave a 150 × 150 file of 90,122 bytes for the square sticker.Values: 1–20000 |
ScaleProportionsboolean, default true | If false, the bitmap takes the exact width and height you send, distorting the art (200 × 100 is 80,122 bytes). |
ScaleIfLargerboolean, default false | If true, only downsizing happens. |
ScaleImageboolean, default true | If false, the requested size is cut from the top-left corner rather than scaled. |
ColorSpaceenum, default default | gray and monochrome change the pixel values only: the sticker's BMP keeps its alpha, 32 bits per pixel and the same 409,722 bytes. rgb doesn't drop the alpha either, because the canvas uses it.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
ImageResolutioninteger | Stored as pixels per meter in the header. 300 writes 11,811; without it both fields are 0, although the KRA says 300 ppi.Values: 10–800 |
FileNamestring | Replaces rocket-sticker in the returned rocket-sticker.bmp. |
StoreFileboolean, default false | Keeps the bitmap for 3 hours and sends a link; useful for files this size. |
What carries over, and what doesn't
Kept
- Exact pixels: the bitmap decodes to the same values as our PNG of the same KRA
- The alpha channel, stored with BI_BITFIELDS masks in a 108-byte BITMAPV4 header
- Partial transparency: the shadow's alpha of 89 is still 89
- Canvas size 320 × 320 unless resized
Lost or not yet supported
- Compression: 409,722 bytes for 320 × 320, where the PNG of the same merge is 27,925.
- Predictable display of alpha: the bytes are right, but whether a reader uses the fourth channel is up to the reader, and we have not compared viewers.
- The file's 300 ppi, unless you send
ImageResolution. - Krita's vector, filter and fill layers, which are not drawn.
- Depth above 8 bits per channel and the color profile.
Limits
- One KRA in, one BMP out, canvas up to 100,000,000 pixels and no wider or taller than 300,000 px.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- The conversion is cut off after 120 seconds with a 504.
- 32-bit when any pixel is transparent, 24-bit when none is. There is no option to choose the depth, and no paletted BMP.
Where teams use it
Windows tools that read BMP
When a Windows program, a display driver or a modding tool loads only BMP, convert the painting straight from Krita's format instead of exporting it by hand each time.
Raw pixels without a decoder
A BMP is easy to read with a few lines of code: a fixed header, then 3 or 4 bytes per pixel. Useful for microcontroller screens or test fixtures generated from artwork.
Questions
Does the BMP keep transparency from Krita?
Yes. Each pixel has an alpha byte, described by bit masks in a BITMAPV4 header, and the values match the merged layers exactly. Whether a viewer honors that alpha depends on the viewer.
Why is the BMP so much bigger than the KRA?
BMP stores every pixel uncompressed, 4 bytes each when the canvas has transparency. The 110,341-byte sample KRA, mostly empty canvas, becomes 409,722 bytes: 122 bytes of headers plus 320 × 320 × 4.
When do I get a 24-bit BMP?
When the merged canvas is fully opaque. A 128 × 96 test KRA with no transparent pixels came back as a 24-bit BMP with the 40-byte header: 36,918 bytes, 54 of headers plus 3 per pixel. Any transparency, like the sticker's empty canvas, keeps the file at 32 bits; AlphaColor doesn't fill it. Paint an opaque background layer in Krita if a tool needs 24-bit.
Convert your first KRA file in a minute.