PNG to PNM API
POST a PNG to /v2/convert/png/to/pnm and get raw RGB pixels behind a short P6 text header, 15 bytes for the sample. The format has no alpha, so every pixel is first blended onto a background: white, or the color in AlphaColor, as the sample does with #F3EFE6.
- Endpoint
- POST /v2/
convert/ png/ to/ pnm - Accepts
- png
- Sample timing
- 1 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/png/to/pnm \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@garden-plot-badge.png \
--form-string 'AlphaColor=#F3EFE6' \
-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/png/to/pnm",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("garden-plot-badge.png", "rb"))],
data={
"AlphaColor": "#F3EFE6",
},
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 = "garden-plot-badge.png";
form.append("File", new Blob([await readFile(file)]), file);
form.append("AlphaColor", "#F3EFE6");
const url = "https://api.pdfconversionapi.com/v2/convert/png/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.001,
"Files": [
{
"FileName": "garden-plot-badge.pnm",
"FileExt": "pnm",
"FileSize": 270015,
"FileData": "UDYKMzAwIDMwMCAyNTUK8+/m…"
}
]
}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
- garden-plot-badge.png (39 KB)
- Output
- garden-plot-badge.pnm (264 KB)
- Source
- A round garden-plot sticker with a QR code, a transparent background and a soft drop shadow, drawn by us for these pages. (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 the PNG is blended onto. The sample's transparent corners become (243, 239, 230), and its 24/255-opaque shadow pixel blends to (221, 217, 209). Unknown names such as beige return 400.Values: white, black, red, green, blue, gray, #RRGGBB or R,G,B |
BackgroundColorstring, default white | Same job, read only when AlphaColor is missing; with both sent, AlphaColor wins (#000000 beat #FFFFFF in our test).Values: As AlphaColor |
ImageWidthinteger | Width of the output grid; 150 gives 150 × 150 and 67,515 bytes.Values: 1–20000 |
ImageHeightinteger | Height; with a width, the art is fitted into the box (200 × 100 gives 100 × 100).Values: 1–20000 |
ScaleProportionsboolean, default true | false fills the given width and height exactly. |
ScaleIfLargerboolean, default false | true stops enlargement of small PNGs. |
ScaleImageboolean, default true | false crops the top-left area rather than scaling, then flattens it. |
ImageInterpolationboolean, default false | Checked, then left alone: any resize of the badge uses Lanczos3 filtering, so ImageWidth=150 produced the same 67,515 bytes with true, with false and with nothing sent. A value such as maybe returns 400. |
ImageResolutioninteger | Validated but never stored, because the PPM header has no density field: 300 returned the default 270,015-byte file unchanged, and 9 is refused with 400. The 144 dpi recorded in the source PNG is dropped as well.Values: 10–800 |
ColorSpaceenum, default default | gray writes a one-channel P5 graymap after the blend, a third of the size (90,015 bytes for the sample); monochrome does the same with only the values 0 and 255.Values: default, rgb, gray, monochrome; cmyk refused |
FileNamestring | Output name; default garden-plot-badge.pnm. |
StoreFileboolean, default false | true for a 3-hour download link instead of base64. |
What carries over, and what doesn't
Kept
- Soft edges, blended by opacity rather than cut: the shadow fades into the background color
- Every opaque pixel exactly
- The pixel grid, unless you resize
Lost or not yet supported
- Transparency, by design: the format has no alpha channel, so each pixel is stored as three blended color bytes.
- 16-bit depth: a 16-bit gray PNG came back as an 8-bit
P6file with a maximum value of 255 and three equal channels. - Size: 270,015 bytes against the 40,051-byte PNG.
- Color profiles, text chunks, DPI and animation frames after the first.
Limits
- One PNG per request.
- Request bodies up to 10 MB on the Free plan or 100 MB on paid plans.
- Images up to 100,000,000 pixels.
- Resize range 1 to 20,000 px.
- 120 seconds per conversion.
Where teams use it
Flattening UI art for tools without alpha support
Pick the background the graphic will sit on, flatten once, and hand plain RGB to tools that ignore alpha.
A lossless step before another format
Flatten a transparent PNG onto a page color here, then convert the PNM to BMP or GIF. Those routes have no AlphaColor, so this is how to get an opaque file with a chosen background from them.
Questions
What happens to transparent pixels?
Each pixel is mixed with the background in proportion to its opacity: fully clear pixels take the background exactly, half-clear ones end up halfway. With no color sent the background is white.
Can I keep the alpha channel?
Not on this route. The P6 and P5 files it writes have no alpha channel, so the PNG is always blended onto a background. Use png-to-tga, png-to-tiff or png-to-webp to keep transparency without loss.
Is the file P6 or P7?
P6, binary PPM. The header is P6, 300 300 and 255 on three lines, 15 bytes for the sample, and 270,000 bytes of RGB follow. With ColorSpace=gray or monochrome the file is a P5 graymap with one byte per pixel instead.
Does TransparentColor work here?
No. It isn't applied to PNM output, and the file came back byte-identical with it.
Convert your first PNG file in a minute.