PDN to WebP API
POST a .pdn to /v2/convert/pdn/to/webp and get a lossless WebP (VP8L) of the merged layers. It decodes to exactly the pixels and alpha of the PNG route, in fewer bytes for the sample.
- Endpoint
- POST /v2/
convert/ pdn/ to/ webp - Accepts
- pdn
- 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/pdn/to/webp \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@lemonade-stand-sign.pdn \
-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/pdn/to/webp",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("lemonade-stand-sign.pdn", "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 = "lemonade-stand-sign.pdn";
form.append("File", new Blob([await readFile(file)]), file);
const url = "https://api.pdfconversionapi.com/v2/convert/pdn/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.024,
"Files": [
{
"FileName": "lemonade-stand-sign.webp",
"FileExt": "webp",
"FileSize": 65432,
"FileData": "UklGRpD/AABXRUJQVlA4TIP/…"
}
]
}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
- lemonade-stand-sign.pdn (87 KB)
- Output
- lemonade-stand-sign.webp (64 KB)
- Source
- A 360 x 240 price sign with rounded transparent corners that we drew and wrote as a layered PDN file ourselves: seven layers, including Overlay and Multiply blend modes, a semi-transparent shine and a hidden draft layer. (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 WebP; ImageWidth=180 gave 180 × 120 at 33,490 bytes, still lossless after the resize.Values: 1–16384 |
ImageHeightinteger | Height in pixels; alone it sets the width from the 3:2 canvas, with a width it is a box.Values: 1–16384 |
ScaleProportionsboolean, default true | false stretches to the exact box: 240 × 240 in 62,042 bytes. |
ScaleIfLargerboolean, default false | true keeps a small canvas at its own size rather than enlarging it. |
ScaleImageboolean, default true | false keeps the top-left region: 180 × 90 gave 10,618 bytes. |
ColorSpaceenum, default default | gray gives 26,884 bytes and monochrome 3,694; the corners stay clear in both.Values: default, rgb, gray, monochrome (also srgb, truecolors, grayscale); cmyk returns 400 |
TransparentColorstring | Clears one exact color: #FFDC5C removed the board's flat yellow, leaving 30,185 clear pixels in 67,376 bytes.Values: #RRGGBB, R,G,B or white, black, red, green, blue, gray |
FileNamestring | Base name of the result; without it the file comes back as lemonade-stand-sign.webp. |
StoreFileboolean, default false | true returns a link valid for 3 hours instead of the file in the JSON. |
What carries over, and what doesn't
Kept
- Every pixel and every alpha value: the WebP decodes to exactly the PNG route's output, soft edges included
- Blend modes and layer opacity, applied before encoding
- The full 360 × 240 size unless you resize
Lost or not yet supported
- Lossy compression is not offered:
ImageQuality=50gave the same 65,432 bytes. - DPI:
ImageResolutionis accepted and changes nothing, since the file has no resolution field. - Layers, hidden layers and metadata: the file is one VP8L chunk.
Limits
- One PDN per request; merged canvas up to 100,000,000 pixels.
- 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 are accepted from 1 to 20,000 px, yet a WebP side can be at most 16,384 px. The sign 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, while 16,384 × 100 converted (1,509,522 bytes).
Where teams use it
Web graphics with soft edges
Signs, stickers and buttons drawn in Paint.NET can be published as WebP with their anti-aliased, partly clear edges intact, without a manual export.
Smaller lossless copies
Where PNG copies of .pdn files take up space, lossless WebP holds the same pixels in less: 65,432 bytes against 72,204 for the sample.
Questions
Is the WebP lossy?
No, lossless. The file holds one VP8L chunk, and decoding it gives the same 86,400 pixels as the PNG route, alpha included. There is no lossy option on this route yet.
Do the soft edges survive?
Yes. WebP stores 8-bit alpha, so the 3,866 partly clear pixels along the sign's edge keep their values. In a GIF of the same file they turn solid.
Why is the WebP smaller than the PNG?
Both are lossless, and WebP's lossless coding packed this sign tighter: 65,432 against 72,204 bytes. Our XCF test poster showed the same direction, 29,348 against 31,750.
Convert your first PDN file in a minute.