WebP to PNM API
POST a WebP to /v2/convert/webp/to/pnm and get its pixels as an uncompressed Netpbm file with a P6 header and three bytes per pixel. The output has no alpha, so transparent areas are blended onto AlphaColor; the sample uses a dark slate.
- Endpoint
- POST /v2/
convert/ webp/ to/ pnm - Accepts
- webp
- Sample timing
- 3 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/webp/to/pnm \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@guest-badge.webp \
--form-string 'AlphaColor=#1F2937' \
-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/webp/to/pnm",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("guest-badge.webp", "rb"))],
data={
"AlphaColor": "#1F2937",
},
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 = "guest-badge.webp";
form.append("File", new Blob([await readFile(file)]), file);
form.append("AlphaColor", "#1F2937");
const url = "https://api.pdfconversionapi.com/v2/convert/webp/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.003,
"Files": [
{
"FileName": "guest-badge.pnm",
"FileExt": "pnm",
"FileSize": 312015,
"FileData": "UDYKNDAwIDI2MCAyNTUKHyk3…"
}
]
}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
- guest-badge.webp (9.4 KB)
- Output
- guest-badge.pnm (305 KB)
- Source
- A guest pass for a made-up trade show that we drew for this page, saved as a lossy WebP with a transparent background and a soft shadow. (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 | Background that clear and partly transparent pixels are blended onto. #1F2937 gave the badge's clear corners the value (31, 41, 55). A name it doesn't know, such as teal, returns 400.Values: white, black, red, green, blue, gray, #RRGGBB or R,G,B |
BackgroundColorstring, default white | Read when AlphaColor is absent; black gave black corners.Values: Same as AlphaColor |
ImageWidthinteger | Resizes before writing; 200 gave 200 × 130 and 78,015 bytes.Values: 1–20000 |
ImageHeightinteger | Height, alone or with ImageWidth as a box.Values: 1–20000 |
ScaleProportionsboolean, default true | false resizes to the exact box, ignoring the 400 × 260 shape. |
ScaleIfLargerboolean, default false | true turns resizing into shrink-only. |
ScaleImageboolean, default true | false crops instead of resizing. |
ImageInterpolationboolean, default false | Accepted with either value; resizing uses Lanczos. |
ColorSpaceenum, default default | gray and monochrome blend onto the matte first, then write a one-channel PGM (P5): 104,015 bytes for the badge instead of 312,015. cmyk returns 400.Values: default, rgb, gray, monochrome |
ImageResolutioninteger | Validated, not stored: the header has no resolution field.Values: 10–800 |
FileNamestring | Output name; guest-badge.pnm by default. |
StoreFileboolean, default false | true keeps the file for 3 hours and returns a URL instead of base64. |
What carries over, and what doesn't
Kept
- The decoded colors, blended exactly: the sample equals the reference decode composited over #1F2937, pixel for pixel.
- The soft shadow's look against the chosen matte, since partly transparent pixels are mixed by their alpha rather than cut off.
- Readability of the QR code, which still decodes from the PNM.
- 400 × 260 pixels in top-to-bottom rows after a 15-byte header.
- EXIF orientation, turned into the pixels: a 300 × 200 WebP tagged 6 came out 200 × 300.
Lost or not yet supported
- The alpha channel itself. Once blended, the corners can't be made transparent again.
- Compression: 9,596 bytes of WebP became 312,015 bytes, 32 times larger.
- Animation frames after the first, and the WebP's EXIF, XMP and ICC data.
Limits
- One WebP per request.
- Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
- WebPs above 100,000,000 pixels return 413 before decoding.
- Conversions that take longer than 120 seconds return 504.
Where teams use it
Raw pixels for processing scripts
Some image-processing code and classroom exercises read Netpbm because the pixels follow a short text header. Decode web images to that layout on the server instead of adding a WebP library.
Flattening transparent images onto a known color
Pipelines that can't handle alpha get a fully opaque image, with the matte color picked to match the page or canvas it will sit on.
Questions
What happens to transparency?
PNM output has no alpha, so each pixel is mixed with AlphaColor according to its alpha. Left out, the matte is white. The sample sends #1F2937, so the clear corners are (31, 41, 55) and the shadow fades into that slate.
Is it a P6 PPM?
Yes. The file starts with P6, then 400 260 and 255 on their own lines, and the RGB bytes follow: 312,015 bytes in all. It is not the PAM (P7) layout, so readers limited to P1 to P6 open it.
Which color names can I use?
white, black, red, green, blue and gray, plus #RRGGBB and R,G,B. Anything else returns 400, for example "'teal' is not a color (use white, black, red, green, blue, gray, #RRGGBB or R,G,B)".
Can I get a gray PGM file?
Yes. ColorSpace=gray writes a P5 graymap with one byte per pixel, 104,015 bytes for the badge, after blending onto AlphaColor. monochrome writes the same layout holding only 0 and 255.
Convert your first WebP file in a minute.