
Diagnosing and Repairing Color Banding Introduced by Image Format Conversions
Founder · Techstars '23
As someone who built and maintains a browser-based image conversion tool used by thousands of users, I see the same problem every week: an image is converted and the result shows smooth gradients broken into visible steps. That phenomenon, color banding, is especially common when images move between formats with different bit depths, chroma subsampling, or compression strategies. In this post I will show how to diagnose banding introduced by image format conversions and, more importantly, how to fix color banding in practical workflows — whether you are optimizing product photos for an ecommerce catalog, archiving photos from a DSLR, or improving images to help your site hit Core Web Vitals targets.
Why color banding appears after conversions
Color banding happens when a smooth gradient contains fewer distinct color values than the human eye expects. Conversions can introduce banding for several technical reasons: a drop in bit depth, chroma subsampling, aggressive quantization in lossy codecs, or metadata and color-profile mishandling. Understanding the root cause is the first step to fix color banding effectively.
Bit depth changes and quantization
Bit depth determines how many discrete values a color channel can represent. An 8-bit image offers 256 levels per channel; a 16-bit image offers 65,536. When you convert a 16-bit TIFF or RAW image to an 8-bit format like baseline JPEG, you introduce quantization. That reduces the number of available colors along gradients and can turn a smooth ramp into visible steps.
Chroma subsampling and color accuracy
Many lossy formats, especially JPEG, use chroma subsampling to reduce color resolution while preserving luminance resolution. Subsampling may not directly produce banding in grayscale ramps, but in photographs with subtle hue shifts subsampling can distort gradients and make steps visible where none existed.
Compression and quantization tables
Lossy compressors use quantization to reduce detail in frequency space. Aggressive settings compress away high-frequency variations that help mask banding. Two conversions, each lossy, compound quantization error and make banding worse than a single conversion.
Color profiles, gamma and viewing differences
If color profile or gamma data is lost or misinterpreted during conversion, gradients will be rendered with incorrect midtone mapping, which may look like banding. Always check whether an ICC profile was preserved and whether the target format supports or expects a profile.
Diagnosing banding: a methodical approach
To fix color banding you must first reproduce and isolate it. These steps walk you through a diagnostic workflow I use at WebP2JPG when users report banding after conversion.
- Compare original and converted images pixel-for-pixel. Open both images in an editor that supports zooming to 100% and pixel inspection (for example, a modern photo editor). Note where banding appears: is it global, in shadows, or on smooth skies and gradients?
- Inspect bit depth and color profile. Use a tool like ImageMagick identify or a library API to show the original and converted bit depth and embedded ICC profile. For example, with ImageMagick:Leave a paragraph here for spacing and readability.
identify -verbose original.tiff | grep -E "Depth|Profile"
- Check for multiple lossy passes. If the file was saved as a lossy format more than once, artifacts stack. Ask whether the conversion pipeline performed more than one lossy encode.
- Look for gamma or profile mismatch. Open both images in a color-managed viewer and in a non-color-managed viewer. If they look different, there's a profile or gamma issue.
- Examine compression settings. For JPEG check quality and subsampling. For WebP or AVIF inspect quantizer settings, chroma, and lossless flags.
After diagnosis you will usually find one or more of: bit depth downsampling, double lossy conversions, or profile stripping. The rest of this post shows targeted fixes for each cause and workflows that avoid introducing banding in the first place.
Fix strategies, ranked by effectiveness
Here are the practical strategies to fix color banding ordered roughly from most to least effective in preserving gradient smoothness.
- Preserve higher bit depth when possible (restore bit depth). Convert workflows to use 16-bit PNG or TIFF as intermediate storage when edits are needed. That prevents quantization during intermediate saves.
- Use lossless encodes or higher-quality lossy settings. If the destination format supports lossless or higher bit depth (for example, PNG-16, lossless WebP, or AVIF with 10/12-bit), prefer those. For JPEG, use quality values high enough that quantization does not clip smooth ramps.
- Apply dithering to mask banding. Dithering spreads quantization error spatially and makes steps less visible. Proper dithering algorithms retain the subjective perception of smoothness.
- Avoid repeated lossy conversions; use master originals. Keep a canonical, high-bit-depth master and generate derivatives from it each time to avoid compounding compression artifacts.
- Manage color profiles and gamma. Ensure ICC profiles are preserved or properly converted to the working space. Correct handling keeps gradients mapped correctly across displays.
Next sections provide concrete commands, code samples, and configuration options for each strategy.
Restore bit depth and format choices
If your source is high-bit-depth (RAW, 16-bit TIFF), converting directly to an 8-bit target loses precision. There are two approaches: keep high bit depth through your processing pipeline, or use targeted techniques to preserve as much tonal resolution as possible when you must drop to 8-bit.
Formats with higher bit-depth support
Use formats that can carry more precision if the target workflow allows:
- PNG supports 16-bit per channel images and alpha; useful for preserving gradients where file size is not the primary constraint.
- TIFF is the archival standard often used by photographers and supports a variety of bit depths and compression options.
- AVIF supports higher bit depths (10-bit, 12-bit and beyond depending on encoder implementation) and modern compression; it can be a good choice for high dynamic range workflows.
- WebP typically stores 8-bit per channel in practice, though it offers lossless modes that can avoid extra quantization.
When converting to a web-target format, choose the highest-quality variant the format supports: PNG-16, AVIF with 10/12-bit, or lossless WebP, depending on browser and environment constraints.
Restore bit depth with ImageMagick and Sharp
Use tools that preserve or explicitly set depth. Examples below show how to export a 16-bit PNG from an original TIFF using ImageMagick and sharp in Node.js.
# ImageMagick: convert TIFF to 16-bit PNG
magick original.tiff -depth 16 -strip -alpha off output-16bit.png
# Sharp (Node.js): read 16-bit TIFF, write 16-bit PNG
const sharp = require("sharp");
sharp("original.tiff")
.png({ bitdepth: 16, compressionLevel: 9 })
.toFile("output-16bit.png")
.then(() => console.log("Saved 16-bit PNG"))
.catch(err => console.error(err));
Those commands preserve higher precision between edits. If you must deliver 8-bit derivatives for the web, keep a master copy and generate 8-bit versions only at the final deliverable step.
Dithering techniques to fix color banding
Dithering adds deliberate noise to spread quantization error and make gradients appear smoother. It is a powerful tool to fix color banding when you must reduce bit depth or use lossy formats. There are two broad classes of dithering: ordered and error-diffusion. Each has tradeoffs.
Ordered dithering
Ordered dithering uses a fixed pattern matrix to modulate pixel values. It is fast and predictable, and produces a texture that may be acceptable for illustrations but can be objectionable on photographs at large sizes.
Error-diffusion dithering (Floyd–Steinberg, Atkinson)
Error-diffusion methods propagate quantization error to neighboring pixels. Floyd–Steinberg is widely used and provides natural-looking noise that conceals banding without producing obvious repetitive patterns. Atkinson dithering is lighter and can be preferable for subtle grain.
Applying dithering with tools
Examples below show pngquant and ImageMagick with error-diffusion. pngquant is excellent for producing optimized 8-bit PNGs with built-in dithering control. ImageMagick supports ordered and Floyd–Steinberg dithering via the -dither option.
# pngquant: convert to 256 colors with Floyd–Steinberg dithering pngquant --quality=80-100 --speed=1 --floyd=1 --output output.png -- original-16bit.png # ImageMagick: apply Floyd–Steinberg dithering when reducing to 8-bit magick original.png -colors 256 -dither FloydSteinberg output-8bit.png
When using JPEG as the final format, you can apply dithering while converting to an indexed intermediate or add film grain/noise pre-quantization to mitigate banding. Below shows a technique to add subtle noise in sharp (Node.js) before JPEG encode.
// Sharp: add low-amplitude noise before JPEG to reduce banding
const sharp = require("sharp");
sharp("input.png")
.normalize() // tone mapping if needed
.modulate({ brightness: 1 }) // chainable
.composite([{ input: Buffer.alloc(0) }]) // placeholder technique for custom noise
// A practical approach is to add a tiny gaussian-noise layer using raw overlay
.jpeg({ quality: 92 })
.toFile("output.jpg");
The example shows conceptually where to inject noise. In practice you generate a noise image programmatically and composite it with low opacity. The goal is to keep noise amplitude below the perceptual threshold so it hides banding without making the image look grainy.
Compression settings and format-specific advice
Each format behaves differently when it comes to gradients. Knowing the format characteristics lets you choose settings that minimize banding.
| Format | Lossy/Lossless | Typical Bit Depth | Alpha Support | When to use |
|---|---|---|---|---|
| JPEG | Lossy | 8-bit | No | Photographs where file size must be small |
| PNG | Lossless | 8-bit, 16-bit | Yes | Graphics, or when preserving gradients matters |
| WebP | Lossy & lossless | Typically 8-bit | Yes | Balanced web use with transparency support |
| AVIF | Lossy & lossless | Supports 8/10/12-bit | Yes | High-efficiency web images, HDR workflows |
| TIFF | Lossless (and lossy variants) | 8/16/32-bit channels | Yes | Archival and professional workflows |
Use the table above as a quick reference. For web delivery, AVIF can preserve more tonal range than JPEG or WebP at similar sizes if the encoder and client support it; otherwise consider lossless WebP or PNG-16 for critical gradients.
JPEG-specific tips
For JPEG, avoid subsampling 4:2:0 on images with large uniform color fields or use higher quality settings. Many encoders allow you to specify chroma subsampling explicitly. Keep quality above 90 for gradients if file size permits.
AVIF and WebP encoder options
Use advanced encoder options to control quantization and color depth. For libavif/avifenc, specify higher bit depth and tune end usage. For cwebp, consider lossless or set a high quality value and experiment with method and alpha settings.
Step-by-step repair workflows
Below are reproducible, practical repair sequences to fix banding depending on your constraints: whether you have the original master and can re-export, or you only have the final compressed file to work with.
Scenario A: You have the master (RAW or 16-bit TIFF)
- Convert RAW to a 16-bit intermediate and perform edits there.
- If delivering for web, export to an appropriate modern format: AVIF with 10/12-bit or lossless WebP/PNG-16 as required.
- If JPEG is required, apply a 16-bit to 8-bit tonal mapping with a slight amount of high-frequency noise or apply subtle dithering before final JPEG encode.
Example with RawTherapee or a command-line pipeline: export 16-bit TIFF from your raw developer, then use an encoder with controlled settings to create web assets.
Scenario B: You only have an 8-bit compressed file
Recovering from an already compressed 8-bit file is harder. You cannot restore lost tones, but you can mask banding with processing:
- Upsample to a higher bit depth container (e.g., open and save as 16-bit PNG) so subsequent edits have more internal precision for filtering.
- Apply a subtle noise or grain layer at low opacity (1–3%) and blend mode such as overlay or normal at low opacity to break visible bands.
- Use a small blur and contrast-preserving techniques followed by a remap to even out steps if the banding is localized.
- Re-encode with a format and settings that preserve the result (lossless PNG or high-quality JPEG/AVIF).
This is the pragmatic path I use when users upload a banded file to WebP2JPG and ask for better output. We bias toward non-destructive filters and subtle dithering rather than heavy-handed editing that changes the look of the image.
# Example using ImageMagick to add subtle noise and re-encode losslessly magick input.jpg -depth 16 -attenuate 0.5 +noise Gaussian -colorspace sRGB output-16bit.png # Then use pngquant or cwebp depending on target, with dithering pngquant --quality=80-100 --speed=1 --floyd=1 --output final.png -- output-16bit.png
Always keep the original compressed file and save your repaired files as new assets so you can compare and iterate.
Practical examples and code snippets
Below are concise, real-world examples you can adapt into scripts or build into a conversion service.
Node.js + sharp: automated repair pipeline
This example reads an input, converts to a high-bit intermediate, applies subtle dither via a noise overlay, and writes a high-quality JPEG. It is designed for automated image pipelines used in e-commerce or CMS environments.
// repair-pipeline.js
const sharp = require("sharp");
const fs = require("fs");
async function repair(inputPath, outputPath) {
const image = sharp(inputPath);
const metadata = await image.metadata();
// Convert to 16-bit PNG in-memory to maintain headroom
const highBit = await image
.ensureAlpha() // keep alpha if present
.png({ bitdepth: 16 })
.toBuffer();
// Generate subtle noise overlay at very low amplitude
const { width, height } = metadata;
const noise = Buffer.alloc(width * height * 4);
for (let i = 0; i < noise.length; i++) {
noise[i] = 128 + Math.round((Math.random() - 0.5) * 6); // tiny amplitude
}
// Composite noise at low opacity and export high-quality JPEG
await sharp(highBit, { raw: { width, height, channels: 4 } })
.composite([{ input: noise, raw: { width, height, channels: 4 }, blend: "over", opacity: 0.02 }])
.jpeg({ quality: 92, chromaSubsampling: "4:4:4" })
.toFile(outputPath);
}
// Usage
repair("input.jpg", "repaired.jpg").catch(console.error);
The script intentionally sets chromaSubsampling to 4:4:4 and keeps quality high to minimize additional banding. The noise amplitude is tiny to avoid visible grain but sufficient to break uniform steps.
Shell pipeline: convert high-bit master to web variants
An example pipeline for an e-commerce workflow that keeps a master and produces JPEG and AVIF web derivatives:
# 1. Produce a 16-bit PNG master from RAW via your raw processor (manual step) # 2. Generate AVIF with high bit depth where supported avifenc --min 0 --max 63 --cq-level 30 --minalpha 0 master-16bit.png product.avif # 3. Generate a high-quality JPEG fallback with minimal subsampling magick master-16bit.png -sampling-factor 4:4:4 -quality 92 product.jpg # 4. WebP lossless as an alternative cwebp -lossless master-16bit.png -o product.webp
Tune cq-level, quality and encoder options based on your visual tolerance and file-size targets. Always compare derivatives at 100% zoom and on the target display pipeline.
Troubleshooting common problems
Even with careful pipelines, problems occur. Below are common issues and how to address them.
- Banding appears only in web browsers: Check whether the browser is applying color management differently. Compare in Chrome, Firefox and an image editor. Tools like the developer tools color profile emulation can help. See MDN on color management for guidance.
- Banding created after an automated conversion service: Confirm the service keeps the master or performs lossy re-encodes. Consider replacing that stage with a transform that preserves bit depth or adds dithering.
- Noise made image look grainy after dithering: Reduce amplitude and use an error-diffusion algorithm instead of uniform noise. Test at device scale to ensure acceptability.
- Different displays show different severity: Color depth and panel processing vary by device. Test on a high-quality monitor to set a baseline, but be pragmatic about average devices used by your audience.
- Legacy clients don’t support AVIF: Use client hints or content negotiation and provide JPEG or WebP fallbacks. Services like WebP2JPG can help with conversions and fallback generation.
When troubleshooting, keep a changelog of each conversion step and setting so you can reproduce the pipeline and validate fixes.
Integrating into development and design workflows
Practical teams need repeatable, automated pipelines that avoid introducing banding. Here are workflow patterns I recommend from building WebP2JPG and working with enterprise clients.
Source of truth master asset
Store a canonical high-bit-depth master in your DAM or object storage. Never overwrite the master. Derivatives should be generated on demand from that master to avoid accumulated losses.
Build-time image generation for web
Generate web derivatives during your CI/CD or asset pipeline. This allows consistent encoder settings and automated testing for visual regressions. Use visual diffing tools to detect introduced banding at build time.
Client-side considerations
Deliver the best format the client supports via content negotiation or picture element fallbacks. For dynamic resizing use a server or CDN that supports high-quality resampling and doesn't re-encode with lossy defaults.
For example, when optimizing product images for ecommerce, serve AVIF to supporting clients and JPEG/WebP fallback to others. If your hosting or CDN can't produce AVIF without quality loss, pre-generate assets and store them instead.
For photographers archiving their work, keep RAW/TIFF masters and generate print or web derivatives only when needed. If you're a web developer improving Core Web Vitals, balance format efficiency with visual fidelity: small artifacts in large gradients may be more noticeable than a small file-size saving.
Comparison: quantization, bit-depth and banding sensitivity
The table below summarizes how quantization level and bit depth affect banding sensitivity for common image types. This is not a benchmark but a guideline based on format specifications.
| Image Type | Susceptible to Banding | Primary Cause | Recommended Output |
|---|---|---|---|
| Smooth gradient sky | High | Low bit depth, aggressive quantization | PNG-16, AVIF 10/12-bit, lossless WebP |
| Product photo with texture | Medium | Chroma subsampling + quantization | High-quality JPEG or AVIF, 4:4:4 chroma if possible |
| Flat UI gradients | High | 8-bit rendering & lack of dithering | Use CSS gradients instead of raster images, or PNG-16 |
Where possible, replace raster gradients with CSS gradients for UI backgrounds. That avoids raster banding entirely and is often the best approach for web development.
Tools and resources
The following stable resources are useful when diagnosing and fixing banding. They provide authoritative information about formats, browser support, and best practices.
- MDN Web Docs: Multimedia format guides
- Can I Use: browser compatibility for AVIF, WebP and others
- W3C/WHATWG specifications and recommendations
- Cloudflare Learning Center: Image optimization and delivery
- web.dev: performance and image best practices
For practical conversion tools, I recommend trying WebP2JPG as a simple, web-based option for converting user uploads while preserving sensible defaults. For programmatic pipelines, use ImageMagick, libvips/sharp and modern AVIF encoders.
If you need a quick conversion or to batch-repair a set of banded images, check WebP2JPG.com for a browser-based experience that preserves useful settings and includes fallbacks. For headless pipelines consider integrating conversion APIs or using tools above.
You can also use WebP2JPG.com as a reference for default settings and to compare outputs quickly when troubleshooting customer issues in a support workflow.
FAQ
Q: I converted to WebP and now see more banding. How fix color banding?
A: WebP can be encoded lossless or lossy. Re-encode using lossless WebP for critical gradients, or increase lossy quality and disable chroma subsampling if your encoder allows. If you started from a high-bit-depth master, export to a format that supports similar precision such as AVIF or PNG-16 instead.
Q: Will adding noise change my image too much?
A: When applied at very low amplitude, noise or dithering is imperceptible as grain but very effective at masking banding. Use small amplitudes and test at final display sizes. For product photography or portraits, be conservative to avoid altering perceived image clarity.
Q: Can I automate detection of banding?
A: Yes. A simple approach calculates the gradient variance and looks for long runs of identical values along sample rows or columns. Visual regression and perceptual-difference metrics (SSIM, Delta E) can help flag files that likely have visible banding. Then run a corrective pipeline automatically.
Q: Is AVIF always the best choice to avoid banding?
A: AVIF offers higher bit depth options and efficient compression, which can reduce banding at a given file size. However, encoder maturity, encoding speed, and client support vary. Use AVIF where supported and provide fallbacks; test visually as implementations differ.
Checklist to fix color banding in your pipeline
Use this checklist to audit and harden your image conversion pipeline against banding issues.
- Keep a high-bit-depth master and do not re-encode from derived images.
- Preserve ICC profiles and validate gamma handling on export.
- Prefer lossless or higher bit-depth formats for critical gradients.
- If you must drop bit depth, apply error-diffusion dithering or subtle noise.
- Avoid chroma subsampling on images with large flat color fields; use 4:4:4 if available.
- Automate visual regression testing at 100% zoom for critical assets.
Following these steps will reduce incidents of banding and make it easier to diagnose and repair when it happens.
Closing: pragmatic balance of quality and performance
In product environments we frequently need to balance file size and visual quality. My advice from building consumer-facing conversion tools is practical: preserve masters, choose modern formats where clients support them, and use dithering intelligently when you must reduce precision. When optimizing product images for e-commerce, small visual imperfections can reduce buyer confidence, so test across display types. For photographers archiving work, prioritize fidelity and archival formats. If you're a web developer improving Core Web Vitals, invest in build-time image generation, prefer efficient modern encoders, and only apply size-reducing conversions after visual checks that gradients remain acceptable.
If you want a quick hands-on try, upload a problematic image to WebP2JPG.com and experiment with lossless vs lossy encodes and dithering options. For production pipelines, use the strategies and sample scripts above to automate detection and repair so your site delivers crisp gradients without sacrificing performance.
If you found this useful, share how you fixed a banding case in your workflow or ask for a sample pipeline review. Practical details matter, and small configuration choices often make the difference between a smooth photo and visible banding.
Alexander Georges
Techstars '23Full-stack developer and UX expert. Co-Founder & CTO of Craftle, a Techstars '23 company with 100,000+ users. Featured in the Wall Street Journal for exceptional user experience design.