Add ChromaSubsamplingMethod option for box-average downsampling#33
Open
tylerneylon wants to merge 2 commits into
Open
Add ChromaSubsamplingMethod option for box-average downsampling#33tylerneylon wants to merge 2 commits into
tylerneylon wants to merge 2 commits into
Conversation
Adds an opt-in ChromaSubsamplingMethod::Average that box-averages chroma samples when subsampling, matching libjpeg/libjpeg-turbo's default h2v2_downsample behavior — including its per-column dither of the rounding bias so that rounding error averages to zero across each row. The existing point-sampling behavior remains the default (Nearest), so this is fully backward-compatible. Box-averaging produces noticeably better quality on images with sharp colored edges (screenshots, rendered/antialiased text), where point-sampling can stamp an entire 2x2 block with one outlier pixel's chroma.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Adds an opt-in
ChromaSubsamplingMethod::Averagethat box-averages each chroma block when subsampling, matching libjpeg / libjpeg-turbo's default downsampler. The existing point-sampling behavior stays the default (Nearest), so there is no change for current users.Motivation
When chroma is subsampled (e.g. 4:2:0), each output Cb/Cr sample represents a 2×2 block of source pixels. Today
jpeg-encodertakes the top-left pixel of each block and discards the other three. libjpeg instead averages all four (seejcsample.c::h2v2_downsample).On natural photographs the difference is negligible. On images with sharp colored edges — UI screenshots, rendered text, anti-aliased line art — point-sampling can stamp an entire 2×2 block with one outlier pixel's chroma, producing visible color fringing that box-averaging avoids.
On a mixed set of ~1,500 images (photographs, charts, UI screenshots, rendered text) encoded at quality 75, mean per-pixel-channel |Δ| against libjpeg-turbo's output drops from 0.26 with
Nearestto 0.003 withAverage.What's in this change
ChromaSubsamplingMethod { Nearest, Average }enum andEncoder::set_chroma_subsampling_method.get_block_averagedpath alongside the existingget_block, wired into both the interleaved and progressive encode paths. It's generic over stride, so 4:2:2, 4:1:1, etc. get the same treatment.Compatibility
Default remains
Nearest. No change to output for any existing caller.Related
Tangentially related to image-rs/image#2202 (JPEG encode quality), since
imagenow uses this crate for JPEG encoding.