{"slug": "pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray", "title": "Pillow, sharp or mozjpeg for a white-background product photo? Same quality, different stray pixels", "summary": "A developer benchmarked Pillow, sharp, and sharp's mozjpeg option on three white-background product photos, finding that enabling mozjpeg: true produced files 23–28% smaller at quality 85 with 4:2:0 and reduced stray non-white background pixels from 0.481% to 0.347% on average. Sharp's default and Pillow produced identical stray-pixel shares, while mozjpeg at quality 85 with 4:4:4 matched Pillow's quality-95 stray share in under half the bytes. None of the encoders achieved a fully pure 255 background, which matters for marketplace rules like Amazon's pure-white main-image requirement.", "body_md": "I needed JPEGs of three white-background product photos and had three encoders to hand: Pillow, sharp, and sharp with its `mozjpeg` flag. After saving the same three PNGs all three ways: Pillow and plain sharp leave identical pixels, and the `mozjpeg: true` flag gave smaller files with fewer stray background pixels at the same quality. None of them gets the background to 100% pure 255. Unless I say otherwise the numbers below are means over three photos on one Apple M4 Mac, with Pillow 11.3.0 and sharp 0.34.5. KB here means 1024 bytes.\n\nThe photos are three shots from Wikimedia Commons, not mine: a teddy bear on a blue knit blanket, a Bohemian glass against a grey wall, and a pair of white sneakers on beige tile. All three are CC BY-SA 4.0, with credits under the chart. I made the white-background PNGs in ImgIng ([https://imging.ai/](https://imging.ai/)) in desktop Chromium: AI cutout on the quick setting, background set to white, exported as PNG. Its export row after a cutout lists WEBP, PNG, AVIF, TIFF and GIF with no visible JPG, so everything JPEG below happened afterwards.\n\n\"Background\" means the pixels the cutout left fully transparent. In the PNG every one of them is 255, and I decoded each JPEG with Pillow and counted the ones where any channel is no longer 255. Amazon's US seller help page (viewed 2026-10-23) asks main images for a pure white background, RGB 255, 255, 255, and says JPEG is recommended, which is why I care about that last digit.\n\nAt quality 85 with 4:2:0 chroma sampling, which is the default for both, the stray share was identical for every photo: 0.656% on the sneakers, 0.286% on the teddy bear, 0.503% on the glass. Sharp's files came out a few KB smaller, 210 against 216 KB on the sneakers. The `cjpeg` on my machine is libjpeg-turbo, not mozjpeg, and matched Pillow byte for byte, so I left it out.\n\nImgIng's compress and convert tool is the other way I got JPEG. At 85 its file was within a few KB of sharp's default (211 against 210 KB on the sneakers), and the stray share matched Pillow's at the same quality. Its output measured 4:2:0.\n\nSame quality, same sampling, only `mozjpeg: true` added. Three-photo means:\n\n| Encoder | Quality | Sampling | Mean size | Stray background pixels | \n|---|---|---|---|---|\n| Pillow | 85 | 4:2:0 | 175 KB | 0.481% | \n| sharp default | 85 | 4:2:0 | 165 KB | 0.481% | \n| sharp mozjpeg | 85 | 4:2:0 | 125 KB | 0.347% | \n| Pillow | 95 | 4:4:4 | 304 KB | 0.123% | \n| sharp mozjpeg | 85 | 4:4:4 | 141 KB | 0.114% | \n\nAgainst sharp's default at the same quality and sampling, the mozjpeg files were 38 to 41% smaller at quality 75, 23 to 28% at 85 and 13 to 20% at 95, per photo. The stray share dropped too. The last two rows are the pair I'd point to: mozjpeg at quality 85 with 4:4:4 ended at about the same stray share as Pillow at 95, in under half the bytes.\n\nLook for the orange sharp mozjpeg line sitting lower and further left than every other one in both panels, meaning smaller files with fewer stray pixels. The ImgIng convert line sits on top of the sharp default line in the left panel. Photos by Dan Bollinger, Kritzolina and JustinLiang522 from Wikimedia Commons, CC BY-SA 4.0, adapted here under the same license.\n\nIn Pillow `subsampling` is 2 for 4:2:0 and 0 for 4:4:4. In sharp the mozjpeg switch is one extra key, and nothing else differs between the second and third rows of the table.\n\n```\nsrc.save(\"shoe_pil.jpg\", quality=85, subsampling=2)\nbg = cut == 0   # alpha of the cutout, 0 = left empty\nshare = 100 * (np.array(Image.open(p).convert(\"RGB\"))[bg] != 255).any(axis=1).mean()\n# pil 216 KB  0.656 %   sharp 210 KB  0.656 %   moz 162 KB  0.451 %\njs\nconst opts = { quality: 85, chromaSubsampling: \"4:2:0\" };\nawait sharp(\"shoe_white.png\").jpeg(opts).toFile(\"shoe_sharp.jpg\");\nawait sharp(\"shoe_white.png\").jpeg({ ...opts, mozjpeg: true }).toFile(\"shoe_moz.jpg\");\n```\n\nThe comment is the real output for the sneaker photo.\n\nFor a white product photo I'd use sharp with `mozjpeg: true`, at quality 85 with 4:4:4 when the stray share matters and with 4:2:0 when the file size does. Chroma sampling mattered more than quality in my numbers: moving Pillow from 4:2:0 to 4:4:4 at quality 85 roughly halved the stray share, and going from 85 to 95 at 4:2:0 cut it by about a third.\n\nNothing reached zero. Pillow at quality 100 with 4:4:4 still had 0.035% stray pixels at an average of 538 KB, and mozjpeg at 95 with 4:4:4 had 0.045%. So I'd check the finished JPEG instead of trusting a quality number. That's three photos on one machine, so the numbers aren't a promise about your images. I haven't tried other mozjpeg builds, or checked whether any marketplace rejects a background that reads 254 in a few pixels.", "url": "https://wpnews.pro/news/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray", "canonical_source": "https://dev.to/yue_shu_c621a4a637f22396f/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-different-stray-pixels-1kd3", "published_at": "2026-10-24 08:04:45+00:00", "updated_at": "2026-10-24 08:12:43.797791+00:00", "lang": "en", "topics": ["developer-tools"], "entities": ["Pillow", "sharp", "mozjpeg", "libjpeg-turbo", "ImgIng", "Amazon", "Wikimedia Commons"], "also_reported_by": [], "alternates": {"html": "https://wpnews.pro/news/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray", "markdown": "https://wpnews.pro/news/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray.md", "text": "https://wpnews.pro/news/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray.txt", "jsonld": "https://wpnews.pro/news/pillow-sharp-or-mozjpeg-for-a-white-background-product-photo-same-quality-stray.jsonld"}}