Skip to content
pdfconversionapi

PNM to JPG API

POST a netpbm image to /v2/convert/pnm/to/jpg and get a baseline JPEG back. The sample render, 230,415 bytes as a P6 file, came back as 16,587 bytes at ImageQuality=90, about 7% of its size.

Endpoint
POST /v2/convert/pnm/to/jpg
Accepts
pnm
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/pnm/to/jpg \
  -H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
  -F File=@three-spheres-render.ppm \
  --form-string ImageQuality=90 \
  -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
fi
200 OK1 ms median1 file, 16 KB
{
  "ConversionCost": 1,
  "ConversionTime": 0.001,
  "Files": [
    {
      "FileName": "three-spheres-render.jpg",
      "FileExt": "jpg",
      "FileSize": 16587,
      "FileData": "/9j/4AAQSkZJRgABAgAAAQAB…"
    }
  ]
}

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.

First page of three-spheres-render.jpg, rendered by the API
Input
three-spheres-render.ppm (225 KB)
Output
three-spheres-render.jpg (16 KB)
Source
A 320 x 240 frame from a small ray tracer we wrote for this page (three spheres on a checkered floor), saved as a binary PPM (P6) with 8 bits per channel. (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.

ParameterWhat it does
ImageQualityinteger, default 85Encoder quality. For the render: 7,785 bytes at 50, 10,639 at 75, 13,640 at the default 85 and 16,587 at 90, the sample's setting.Values: 1–100
ColorSpaceenum, default defaultgray writes a one-channel JPEG (9,912 bytes for the render). Without it, even a PGM input is saved with three color channels.Values: default, rgb, gray, monochrome
AlphaColorstring, default whiteOnly matters for PAM files with an alpha channel: their clear and partly clear pixels are blended onto this color. PPM and PGM have no alpha, so it changes nothing for them.Values: A color name, #RRGGBB or R,G,B
BackgroundColorstring, default whiteRead as the blend color when AlphaColor isn't sent.Values: Same as AlphaColor
ImageWidthintegerJPEG width. ImageWidth=128 gave a 128 × 96 thumbnail of 3,632 bytes.Values: 1–20000
ImageHeightintegerJPEG height, or the box height when combined with a width.Values: 1–20000
ScaleProportionsboolean, default truefalse stretches the frame into the exact box.
ScaleIfLargerboolean, default falsetrue makes resizing shrink-only.
ScaleImageboolean, default truefalse crops from the top-left corner instead of scaling.
ImageResolutionintegerStored as the JFIF density in dots per inch; left out, the JPEG records only a 1:1 pixel aspect.Values: 10–800
ImageInterpolationboolean, default falseAccepted; resizing uses Lanczos regardless.
FileNamestringName of the JPEG; defaults to the uploaded file's name.
StoreFileboolean, default falseReturn a URL valid for 3 hours instead of base64.

What carries over, and what doesn't

Kept

  • Colors within a few levels: at quality 90 the largest error against the PPM was 32 levels, the average 1.2
  • Full color resolution, with no chroma subsampling (4:4:4)
  • The 320 × 240 frame size

Lost or not yet supported

  • Exact values, since JPEG is lossy.
  • 16-bit depth. A 16-bit PPM gave the same JPEG, byte for byte, as its 8-bit version.
  • PAM transparency, which is blended onto AlphaColor.
  • The single gray channel of a PGM, unless you send ColorSpace=gray: a test PGM came back as an 11,405-byte color JPEG, and as 9,910 bytes with gray.

Limits

  • One file per request.
  • Requests up to 10 MB on the Free plan or 100 MB on paid plans, all files and fields together.
  • Images over 100,000,000 pixels return 413 before decoding.
  • Each side can be at most 65,500 px, a little under the 65,535 a JPEG header can record: a 65,501 × 2 PPM returned 413 "JPEG images can be at most 65,500 pixels on a side, and this one is 65,501×2", while the 65,500 × 2 one converted.
  • 120 seconds per conversion, then 504.

Where teams use it

Previews of rendered frames

Code that writes PPM frames, such as a renderer or a simulation, can post each frame here for a preview that fits in a web page or a chat message. At quality 90 the sample is 16,587 bytes instead of 230,415.

Uploads to services that want JPEG

Upload forms and print services that accept JPEG but not netpbm files can receive your frames once they are converted, instead of rejecting them.

Questions

What quality is used if I don't send ImageQuality?

85. For the sample render that gives 13,640 bytes; the code samples on this page send 90 for 16,587 bytes.

Why did my grayscale PGM become a color JPEG?

The JPEG is written with three channels unless you ask for gray. Send ColorSpace=gray to get a one-channel JPEG, which is also smaller.

Does a 16-bit PPM give a better JPEG?

No. JPEG here is 8 bits per channel, and the 16-bit test file produced exactly the same bytes as the 8-bit render it was made from. Use /v2/convert/pnm/to/png or /v2/convert/pnm/to/tiff to keep 16 bits.

Convert your first PNM file in a minute.