KRA to WebP API
A POST to /v2/convert/kra/to/webp merges the visible Krita layers and encodes the result as lossless WebP (VP8L), with alpha whenever the canvas has transparency, as the sticker does. Every pixel decodes to the same values as our PNG output of the same file.
- Endpoint
- POST /v2/
convert/ kra/ to/ webp - Accepts
- kra
- Sample timing
- 25 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/webp \
-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/webp",
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/webp";
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.025,
"Files": [
{
"FileName": "rocket-sticker.webp",
"FileExt": "webp",
"FileSize": 24186,
"FileData": "UklGRnJeAABXRUJQVlA4TGVe…"
}
]
}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.webp (24 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 | Pixel width after merging. For a web thumbnail of the sticker, 128 px gave an 8,558-byte WebP and 64 px gave 3,356 bytes.Values: 1–16384 |
ImageHeightinteger | Pixel height. Combined with a width it is a box the canvas is fitted into, 100 × 100 for a 200 × 100 box here.Values: 1–16384 |
ScaleProportionsboolean, default true | Turn it off to force the exact box; 200 × 100 then stretches the rocket sideways (10,704 bytes). |
ScaleIfLargerboolean, default false | When true, a width or height larger than the 320 px canvas is ignored and the WebP stays 320 px. |
ScaleImageboolean, default true | When false, the requested box is cut from the canvas's top-left corner; on this sticker a 120 × 90 cut is empty and only 122 bytes. |
ColorSpaceenum, default default | gray brought the file to 13,186 bytes and monochrome to 5,838; transparency is kept in both.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
TransparentColorstring | One exact color becomes transparent in addition to the canvas's own alpha. #FFFFFF removed 104 pure white pixels, faint edge pixels of the rocket's body; the highlights are tinted by the body and stay.Values: #RRGGBB, R,G,B or a color name |
FileNamestring | Result name without extension; rocket-sticker.webp otherwise. |
StoreFileboolean, default false | Store the WebP for 3 hours and receive Files[].Url rather than the bytes. |
What carries over, and what doesn't
Kept
- Every pixel: the WebP decodes to exactly the values of the PNG made from the same .kra
- Alpha, including the 4,962 partly transparent edge and shadow pixels
- The merged layer stack: opacity, offsets, the masked flame and groups
- The 320 × 320 canvas size unless you resize
Lost or not yet supported
- Nothing at the pixel level for 8-bit files, but
ImageQualityis not read: there is no lossy WebP option, and quality 10 returned the same 24,186 bytes. - Bit depth above 8. WebP holds 8 bits per channel, so a 16-bit Krita canvas is reduced.
- Text and shapes on Krita vector layers, which are not drawn yet.
- Resolution and the color profile: no 300 ppi value and no ICC chunk in the WebP.
Limits
- One KRA file per call; the merged canvas may have up to 100,000,000 pixels and 300,000 px a side, though the WebP itself is capped as below.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- Conversions stop at 120 seconds with a 504.
- Resizing is accepted up to 20,000 px, but the WebP stops at 16,384 px a side. The rocket stretched to 16,385 × 100 returned 413
WebP images can be at most 16,384 pixels on a side, and this one is 16,385×100; lower ImageWidth or ImageHeight, and 16,384 × 100 converted. A 16,385 × 10 canvas sent with no size options gets the message without the advice after the semicolon. - Checked with KRA files from our own writer; files saved by Krita itself are still untested.
Where teams use it
Web galleries for digital painters
Artists who paint in Krita can publish straight from their .kra files: the WebP keeps transparency, so stickers and character cutouts sit on any page background.
Smaller transparent assets than PNG
For the sample, lossless WebP saved 13% over PNG (24,186 against 27,925 bytes) with identical pixels, which matters when an app ships many cutouts.
Automated exports from a shared drive
Watch a folder of Krita sources and write a WebP next to each one when it changes, instead of exporting by hand from the desktop app.
Questions
Is the WebP lossy or lossless?
Always lossless. The sticker comes back as a VP8L stream with the alpha flag set; a fully opaque 128 × 96 test canvas came back as RGB, without the flag. Either way, decoding gives exactly the pixels of the PNG made from the same .kra, so ImageQuality has no effect on this route.
Will the sticker's soft shadow survive?
Yes. Partial transparency is stored as it is: the shadow layer, painted at 35% opacity, keeps its alpha of 89 in the WebP, so it darkens whatever background the image is placed on.
What happens to filter or fill layers in my KRA?
They are left out. Krita's filter, fill, clone, file and vector layers are not rendered yet, and the request still returns 200. Merge them into paint layers in Krita first if they matter.
Convert your first KRA file in a minute.