Skip to content

Commit 982b074

Browse files
committed
Private constants
1 parent 24e2956 commit 982b074

File tree

4 files changed

+47
-33
lines changed

4 files changed

+47
-33
lines changed

src/image.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::attr::Attributes;
22
use crate::blur::{liq_blur, liq_max3, liq_min3};
33
use crate::error::*;
4-
use crate::pal::{f_pixel, PalF, PalIndexRemap, MAX_COLORS, MIN_OPAQUE_A, RGBA};
4+
use crate::pal::{f_pixel, PalF, PalIndexRemap, MAX_COLORS, RGBA};
55
use crate::remap::DitherMapMode;
66
use crate::rows::{DynamicRows, PixelsSource};
77
use crate::seacow::{RowBitmap, SeaCow};
@@ -137,7 +137,7 @@ impl<'pixels> Image<'pixels> {
137137
let mut lastpixel = this_row[0];
138138
let mut lastcol = 0;
139139
for (col, px) in this_row.iter().copied().enumerate().skip(1) {
140-
if uses_background && (colors[px as usize]).a < MIN_OPAQUE_A {
140+
if uses_background && colors[px as usize].is_fully_transparent() {
141141
// Transparency may or may not create an edge. When there's an explicit background set, assume no edge.
142142
continue;
143143
}

src/pal.rs

Lines changed: 28 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,17 +9,14 @@ pub type RGBA = rgb::Rgba<u8>;
99
#[allow(clippy::upper_case_acronyms)]
1010
pub type ARGBF = rgb::Argb<f32>;
1111

12-
pub const INTERNAL_GAMMA: f64 = 0.57;
13-
pub const LIQ_WEIGHT_A: f32 = 0.625;
14-
pub const LIQ_WEIGHT_R: f32 = 0.5;
15-
pub const LIQ_WEIGHT_G: f32 = 1.;
16-
pub const LIQ_WEIGHT_B: f32 = 0.45;
12+
const INTERNAL_GAMMA: f64 = 0.57;
13+
const LIQ_WEIGHT_A: f32 = 0.625;
14+
const LIQ_WEIGHT_R: f32 = 0.5;
15+
const LIQ_WEIGHT_G: f32 = 1.;
16+
const LIQ_WEIGHT_B: f32 = 0.45;
1717

1818
/// This is a fudge factor - reminder that colors are not in 0..1 range any more
19-
pub const LIQ_WEIGHT_MSE: f64 = 0.45;
20-
21-
pub const MIN_OPAQUE_A: f32 = 1. / 256. * LIQ_WEIGHT_A;
22-
pub const MAX_TRANSP_A: f32 = 255. / 256. * LIQ_WEIGHT_A;
19+
const LIQ_WEIGHT_MSE: f64 = 0.45;
2320

2421
/// 4xf32 color using internal gamma.
2522
///
@@ -115,7 +112,7 @@ impl f_pixel {
115112

116113
#[inline]
117114
pub(crate) fn to_rgb(self, gamma: f64) -> RGBA {
118-
if self.a < MIN_OPAQUE_A {
115+
if self.is_fully_transparent() {
119116
return RGBA::new(0, 0, 0, 0);
120117
}
121118

@@ -145,6 +142,16 @@ impl f_pixel {
145142
b: gamma_lut[px.b as usize] * LIQ_WEIGHT_B * a,
146143
})
147144
}
145+
146+
#[inline]
147+
pub(crate) fn is_fully_transparent(self) -> bool {
148+
self.a < 1. / 256. * LIQ_WEIGHT_A
149+
}
150+
151+
#[inline]
152+
pub(crate) fn is_fully_opaque(self) -> bool {
153+
self.a >= 255. / 256. * LIQ_WEIGHT_A
154+
}
148155
}
149156

150157
impl Deref for f_pixel {
@@ -348,6 +355,17 @@ pub fn gamma_lut(gamma: f64) -> [f32; 256] {
348355
tmp
349356
}
350357

358+
/// MSE that assumes 0..1 channels scaled to MSE that we have in practice
359+
#[inline]
360+
pub(crate) fn unit_mse_to_internal_mse(internal_mse: f64) -> f64 {
361+
LIQ_WEIGHT_MSE * internal_mse
362+
}
363+
364+
/// Internal MSE scaled to equivalent in 0..255 pixels
365+
pub(crate) fn internal_mse_to_standard_mse(mse: f64) -> f64 {
366+
(mse * 65536. / 6.) / LIQ_WEIGHT_MSE
367+
}
368+
351369
/// Not used in the Rust API.
352370
/// RGBA colors obtained from [`QuantizationResult`](crate::QuantizationResult)
353371
#[repr(C)]

src/quant.rs

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use crate::hist::{HistogramInternal, Histogram};
44
use crate::image::Image;
55
use crate::kmeans::Kmeans;
66
use crate::mediancut::mediancut;
7-
use crate::pal::{PalF, PalIndexRemap, PalLen, PalPop, Palette, LIQ_WEIGHT_MSE, MAX_COLORS, MAX_TRANSP_A, RGBA};
8-
use crate::remap::{mse_to_standard_mse, remap_to_palette, remap_to_palette_floyd, DitherMapMode, Remapped};
7+
use crate::pal::{PalF, PalIndexRemap, PalLen, PalPop, Palette, MAX_COLORS, RGBA};
8+
use crate::pal::{internal_mse_to_standard_mse, unit_mse_to_internal_mse};
9+
use crate::remap::{remap_to_palette, remap_to_palette_floyd, DitherMapMode, Remapped};
910
use crate::seacow::RowBitmapMut;
1011
use crate::OrdFloat;
1112
use arrayvec::ArrayVec;
@@ -42,9 +43,9 @@ impl QuantizationResult {
4243
if palette_error > max_mse {
4344
attr.verbose_print(format!(
4445
" image degradation MSE={:0.3} (Q={}) exceeded limit of {:0.3} ({})",
45-
mse_to_standard_mse(palette_error),
46+
internal_mse_to_standard_mse(palette_error),
4647
mse_to_quality(palette_error),
47-
mse_to_standard_mse(max_mse),
48+
internal_mse_to_standard_mse(max_mse),
4849
mse_to_quality(max_mse)
4950
));
5051
return Err(QualityTooLow);
@@ -171,7 +172,7 @@ impl QuantizationResult {
171172
/// Approximate mean square error of the palette
172173
#[must_use]
173174
pub fn quantization_error(&self) -> Option<f64> {
174-
self.palette_error.map(mse_to_standard_mse)
175+
self.palette_error.map(internal_mse_to_standard_mse)
175176
}
176177

177178
/// Approximate mean square error of the palette used for the most recent remapping
@@ -180,7 +181,7 @@ impl QuantizationResult {
180181
self.remapped.as_ref()
181182
.and_then(|re| re.palette_error)
182183
.or(self.palette_error)
183-
.map(mse_to_standard_mse)
184+
.map(internal_mse_to_standard_mse)
184185
}
185186

186187
/// Palette remapping error mapped back to 0-100 scale, same as the scale in [`Attributes::set_quality()`]
@@ -333,8 +334,8 @@ fn sort_palette(attr: &Attributes, palette: &mut PalF) {
333334

334335
let mut tmp: ArrayVec<_, { MAX_COLORS }> = palette.iter_mut().map(|(c, p)| (*c, *p)).collect();
335336
tmp.sort_by_key(|(color, pop)| {
336-
let is_transparent = color.a <= MAX_TRANSP_A;
337-
(is_transparent == last_index_transparent, Reverse(OrdFloat::new(pop.popularity())))
337+
let trns = !color.is_fully_opaque();
338+
(trns == last_index_transparent, Reverse(OrdFloat::new(pop.popularity())))
338339
});
339340
palette.iter_mut().zip(tmp).for_each(|((dcol, dpop), (scol, spop))| {
340341
*dcol = scol;
@@ -343,18 +344,17 @@ fn sort_palette(attr: &Attributes, palette: &mut PalF) {
343344

344345
if last_index_transparent {
345346
let alpha_index = palette.as_slice().iter().enumerate()
346-
.filter(|(_, c)| c.a <= MAX_TRANSP_A)
347+
.filter(|(_, c)| !c.is_fully_opaque())
347348
.min_by_key(|(_, c)| OrdFloat::new(c.a))
348349
.map(|(i, _)| i);
349350
if let Some(alpha_index) = alpha_index {
350351
let last_index = palette.as_slice().len() - 1;
351352
palette.swap(last_index, alpha_index);
352353
}
353354
} else {
354-
let num_transparent = palette.as_slice().iter().enumerate()
355-
.filter(|(_, c)| c.a <= MAX_TRANSP_A)
356-
.map(|(i, _)| i + 1) // num entries, not index
357-
.max();
355+
let num_transparent = palette.as_slice().iter().enumerate().rev()
356+
.find(|(_, c)| !c.is_fully_opaque())
357+
.map(|(i, _)| i + 1); // num entries, not index
358358
if let Some(num_transparent) = num_transparent {
359359
attr.verbose_print(format!(" eliminated opaque tRNS-chunk entries...{} entr{} transparent", num_transparent, if num_transparent == 1 { "y" } else { "ies" }));
360360
}
@@ -469,7 +469,7 @@ pub(crate) fn quality_to_mse(quality: u8) -> f64 {
469469
}
470470
if quality >= 100 { return 0.; }
471471
let extra_low_quality_fudge = (0.016 / (0.001 + f64::from(quality)) - 0.001).max(0.);
472-
LIQ_WEIGHT_MSE * (extra_low_quality_fudge + 2.5 / (210. + f64::from(quality)).powf(1.2) * (100.1 - f64::from(quality)) / 100.)
472+
unit_mse_to_internal_mse(extra_low_quality_fudge + 2.5 / (210. + f64::from(quality)).powf(1.2) * (100.1 - f64::from(quality)) / 100.)
473473
}
474474

475475
pub(crate) fn mse_to_quality(mse: f64) -> u8 {

src/remap.rs

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ use crate::error::Error;
22
use crate::image::Image;
33
use crate::kmeans::Kmeans;
44
use crate::nearest::Nearest;
5-
use crate::pal::{f_pixel, PalF, PalIndexRemap, Palette, ARGBF, LIQ_WEIGHT_MSE, MIN_OPAQUE_A};
5+
use crate::pal::{f_pixel, PalF, PalIndexRemap, Palette, ARGBF};
66
use crate::quant::QuantizationResult;
77
use crate::rayoff::*;
88
use crate::rows::{temp_buf, DynamicRows};
@@ -45,7 +45,7 @@ pub(crate) fn remap_to_palette<'x, 'b: 'x>(px: &mut DynamicRows, background: Opt
4545
let (background, transparent_index) = background.map(|background| {
4646
(Some(background), n.search(&f_pixel::default(), 0).0 as PalIndexRemap)
4747
})
48-
.filter(|&(_, transparent_index)| colors[usize::from(transparent_index)].a < MIN_OPAQUE_A)
48+
.filter(|&(_, transparent_index)| colors[usize::from(transparent_index)].is_fully_transparent())
4949
.unwrap_or((None, 0));
5050
let background = background.map(|bg| bg.px.rows_iter(&mut tls_tmp.1)).transpose()?;
5151

@@ -167,7 +167,7 @@ pub(crate) fn remap_to_palette_floyd(input_image: &mut Image, mut output_pixels:
167167
}).transpose()?;
168168

169169
let transparent_index = if background.is_some() { n.search(&f_pixel::default(), 0).0 as PalIndexRemap } else { 0 };
170-
if background.is_some() && palette[transparent_index as usize].a > MIN_OPAQUE_A {
170+
if background.is_some() && !palette[transparent_index as usize].is_fully_transparent() {
171171
background = None;
172172
}
173173
// response to this value is non-linear and without it any value < 0.8 would give almost no dithering
@@ -318,10 +318,6 @@ fn dither_row(row_pixels: &[f_pixel], output_pixels_row: &mut [MaybeUninit<PalIn
318318
}
319319
}
320320

321-
pub(crate) fn mse_to_standard_mse(mse: f64) -> f64 {
322-
(mse * 65536. / 6.) / LIQ_WEIGHT_MSE // parallelized dither map might speed up floyd remapping
323-
}
324-
325321
#[test]
326322
fn send() {
327323
fn is_send<T: Send>() {}

0 commit comments

Comments
 (0)