JPG to PNG API
POST a JPEG to /v2/convert/jpg/to/png and get a PNG holding exactly the decoded photo, with no further loss on later edits. Expect a larger file: the sample sign went from 25,110 to 122,896 bytes. The sample also sends ImageResolution=300 to keep its print size.
- Endpoint
- POST /v2/
convert/ jpg/ to/ png - Accepts
- jpg
- 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/jpg/to/png \
-H "Authorization: Bearer $PDFCONVERSIONAPI_KEY" \
-F File=@trailhead-sign.jpg \
--form-string ImageResolution=300 \
-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/jpg/to/png",
headers={"Authorization": f"Bearer {key}"},
files=[("File", open("trailhead-sign.jpg", "rb"))],
data={
"ImageResolution": "300",
},
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 = "trailhead-sign.jpg";
form.append("File", new Blob([await readFile(file)]), file);
form.append("ImageResolution", "300");
const url = "https://api.pdfconversionapi.com/v2/convert/jpg/to/png";
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": "trailhead-sign.png",
"FileExt": "png",
"FileSize": 122896,
"FileData": "iVBORw0KGgoAAAANSUhEUgAA…"
}
]
}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
- trailhead-sign.jpg (25 KB)
- Output
- trailhead-sign.png (120 KB)
- Source
- A drawn mountain trailhead with a wooden sign and a QR code, made by us for these pages and saved at JPEG quality 92 with an EXIF block, an sRGB color profile and 300 dpi. (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 |
|---|---|
ImageResolutioninteger | Adds a pHYs chunk with this DPI. The JPEG's 300 dpi is not copied on its own, so the sample sends 300 to keep it.Values: 10–800 |
ColorSpaceenum, default default | gray gives an 8-bit grayscale PNG (43,433 bytes for the sample); monochrome gives pure black and white, also 8-bit gray, at 3,433 bytes.Values: default, rgb, gray, monochrome; cmyk returns 400 |
TransparentColorstring | Pixels of exactly this color become transparent and the PNG gains an alpha channel. On a JPEG, compression noise spreads one painted color over many values: #F7F7F7, the panel's most common value, cleared 1,880 pixels and left the rest speckled.Values: Color name, #RRGGBB or R,G,B |
ImageWidthinteger | Width in pixels; 200 gave a 200 × 150 PNG of 40,264 bytes.Values: 1–20000 |
ImageHeightinteger | Height in pixels, or a bounding box together with the width.Values: 1–20000 |
ScaleProportionsboolean, default true | false stretches to the exact width and height. |
ScaleIfLargerboolean, default false | true stops enlargement; an 800 px PNG of this photo is 372,743 bytes. |
ScaleImageboolean, default true | false crops instead of scaling. |
ImageInterpolationboolean, default false | Accepted either way; Lanczos3 does all resizing. |
FileNamestring | Output name; trailhead-sign.png by default. |
StoreFileboolean, default false | true returns a 3-hour link instead of base64. |
What carries over, and what doesn't
Kept
- Every decoded pixel: the PNG matched our decode of the JPEG exactly
- Grayscale JPEGs stay one-channel (a gray input gave an 8-bit gray PNG)
- The upright view of phone photos: a 300 × 200 test photo tagged EXIF Orientation 6 came back as a 200 × 300 PNG, turned as the tag says
- Print size, when you send
ImageResolution - CMYK JPEGs, converted to RGB
Lost or not yet supported
- Compactness: 122,875 bytes at default settings, about five times the JPEG.
- EXIF and the ICC profile.
- The JPEG's damage is kept, not repaired: block artifacts are stored losslessly too.
Limits
- One JPEG per request.
- Request size up to 10 MB on the Free plan or 100 MB on paid plans.
- 100,000,000 pixels per image (413 above that).
- Resizing from 1 to 20,000 px.
- 120 seconds per conversion.
Where teams use it
An editing master that stops further loss
Each JPEG save throws away detail again. Converting once to PNG means crops, annotations and later saves add no new compression damage.
Inputs for tools that take PNG only
When an image diff tool or a design app wants PNG, convert first. The file is pixel-identical to the decoded JPEG, so a comparison measures your changes, not a second encoder's.
Questions
Does converting to PNG improve the quality?
No. It freezes the quality you have. The PNG holds the same pixels the JPEG decodes to, so later edits don't lose more, but artifacts already there stay.
Why is the PNG so much bigger?
PNG compresses without loss, and photo detail and JPEG noise don't compress well that way. The 400 × 300 sample needs 122,875 bytes as PNG against 25,110 as JPEG.
Can I make the white background transparent?
Only where pixels match a color exactly, and JPEGs rarely have exact areas. On the sample, #FCFCFA (the color the panel was drawn in) matched nothing after compression, and #F7F7F7 cleared 1,880 scattered pixels. Real cut-outs need a mask tool before conversion.
Is the DPI kept?
Not automatically. Send ImageResolution and the PNG gets a pHYs chunk; the sample's PNG reports 300 dpi.
Convert your first JPG file in a minute.