AI image to CMYK for print: Pillow convert and what it misses
Image.convert('CMYK') makes a print-mode TIFF from a Sume image in two lines, but it is not color-managed. The code, the gamut risk, and when to ask for an ICC.

Image.convert("CMYK") turns an RGB image from Sume into a four-channel print-mode image, and save("out.tif", compression="tiff_lzw") writes it. It is a naive conversion with no ICC profile and no gamut mapping, so saturated screen colors will print duller than they looked. Use it to produce a file a printer can open, and ask the printer for their ICC profile for anything where color has to match.
What the two lines do
Pillow's CMYK conversion applies a fixed formula to each pixel. It does not know your paper, ink, or press. RGB colors that sit outside what the press can reproduce, such as vivid cyan, electric blue, and neon green, are clipped without warning. The preview on screen will look brighter than the print.
That is acceptable for a draft, a sticker proof, or a printer that does its own conversion. It is not acceptable for packaging with a brand color you promised to match.
Generate large, then convert
Print wants pixels. At 300 dpi, a 4 by 6 inch card needs 1200 by 1800 pixels. Request a high resolution on a model that supports it, keep the master as PNG, and convert only at the end so you can redo the conversion with a better profile later.
import os, io, requests
from PIL import Image
H = {"Authorization": "Bearer " + os.environ["SUME_API_KEY"]}
def gen(**body):
r = requests.post("https://api.sume.com/v1/images", json=body, headers=H, timeout=60)
r.raise_for_status()
if r.status_code == 202:
raise SystemExit("queued, read /v1/jobs/{id}/result: " + r.text)
return r.json()
def fetch(u):
return Image.open(io.BytesIO(requests.get(u, timeout=60).content))
out = gen(model="bytedance-seed/seedream-4.5", aspect_ratio="3:4",
prompt="Botanical illustration of a fern, flat inks, cream paper background")
rgb = fetch(out["data"][0]["url"]).convert("RGB")
rgb.save("master.png")
cmyk = rgb.convert("CMYK")
cmyk.save("print.tif", compression="tiff_lzw", dpi=(300, 300))
print(cmyk.mode, cmyk.size, "cost", out["usage"]["cost"])
back = Image.open("print.tif")
print("reopened as", back.mode)Format and mode facts
JPEG and TIFF both carry CMYK in Pillow. PNG and WebP do not, so a CMYK image saved to those formats fails or must be converted back to RGB.
| Format | Writes CMYK | Note |
|---|---|---|
| TIFF | Yes | Use compression tiff_lzw; many print shops prefer TIFF |
| JPEG | Yes | Some viewers show inverted colors for Adobe CMYK JPEG |
| PNG | No | Keep it for the RGB master |
| WebP | No | Web delivery only |
What this conversion misses
- No ICC profile is attached and none is applied, so the printer sees device numbers, not intent.
- Total ink coverage is not limited. A very dark image can exceed what a press accepts.
- Pure black text or line art becomes four-channel black instead of K-only. Fix it in the prepress tool, not here.
- Spot colors and Pantone matches are not possible.
Safer print hand-off
Send the RGB PNG master plus the CMYK TIFF, and ask the printer which they want. Add bleed before conversion with the mirror padding recipe, and measure brand colors on the RGB master with the delta E check. For small merchandise runs such as the coaster set, the printer's own converter is usually the better last step.
Sources
Related posts
More in Developers
- AI video API: rate limit or concurrency, which stops a batch first
Concurrency binds long before request rate on Sume. Free allows 120 writes a minute but 1 running job; Pro 300 and 4. How to size a batch against both.
- AI video generator app: four server calls, key never on the client
An AI video app on Sume needs four server-side calls: submit, poll, download and balance. The key stays on your server, never in the browser or mobile app.
- AI video generator from image: the URL checklist before you submit
Image-to-video on Sume needs a public HTTPS image URL. Five checks, the two error codes when Sume cannot fetch it, and the first-frame request body.
- AI video generator from text: the three fields that set the price
In a text-to-video request on Sume, model, resolution and duration set the price. Prompt length and aspect ratio do not. Worked Wan 3.0 and Omni numbers.
Written by Sume