1
//! Utility functions for dealing with sRGB colors.
2
//!
3
//! The constant values in this module are taken from <http://www.color.org/chardata/rgb/srgb.xalter>
4

            
5
use crate::rect::IRect;
6
use crate::surface_utils::{
7
    iterators::Pixels,
8
    shared_surface::{ExclusiveImageSurface, SharedImageSurface, SurfaceType},
9
    ImageSurfaceDataExt, Pixel,
10
};
11

            
12
// Include the linearization and unlinearization tables.
13
include!(concat!(env!("OUT_DIR"), "/srgb-codegen.rs"));
14

            
15
/// Converts an sRGB color value to a linear sRGB color value (undoes the gamma correction).
16
#[inline]
17
153890310
pub fn linearize(c: u8) -> u8 {
18
153890310
    LINEARIZE[usize::from(c)]
19
153890310
}
20

            
21
/// Converts a linear sRGB color value to a normal sRGB color value (applies the gamma correction).
22
#[inline]
23
114022059
pub fn unlinearize(c: u8) -> u8 {
24
114022059
    UNLINEARIZE[usize::from(c)]
25
114022059
}
26

            
27
/// Processing loop of `map_unpremultiplied_components`. Extracted (and public) for benchmarking.
28
#[inline]
29
9671
pub fn map_unpremultiplied_components_loop<F: Fn(u8) -> u8>(
30
9671
    surface: &SharedImageSurface,
31
9671
    output_surface: &mut ExclusiveImageSurface,
32
9671
    bounds: IRect,
33
9671
    f: F,
34
9671
) {
35
9671
    output_surface.modify(&mut |data, stride| {
36
185308634
        for (x, y, pixel) in Pixels::within(surface, bounds) {
37
185308634
            if pixel.a > 0 {
38
89304123
                let alpha = f64::from(pixel.a) / 255f64;
39
89304123

            
40
267912369
                let compute = |x| {
41
267912369
                    let x = f64::from(x) / alpha; // Unpremultiply alpha.
42
267912369
                    let x = (x + 0.5) as u8; // Round to nearest u8.
43
267912369
                    let x = f(x);
44
267912369
                    let x = f64::from(x) * alpha; // Premultiply alpha again.
45
267912369
                    (x + 0.5) as u8
46
267912369
                };
47
89304123

            
48
89304123
                let output_pixel = Pixel {
49
89304123
                    r: compute(pixel.r),
50
89304123
                    g: compute(pixel.g),
51
89304123
                    b: compute(pixel.b),
52
89304123
                    a: pixel.a,
53
89304123
                };
54
89304123

            
55
89304123
                data.set_pixel(stride, output_pixel, x, y);
56
96004511
            }
57
        }
58
9671
    });
59
9671
}
60

            
61
/// Applies the function to each pixel component after unpremultiplying.
62
9671
fn map_unpremultiplied_components<F: Fn(u8) -> u8>(
63
9671
    surface: &SharedImageSurface,
64
9671
    bounds: IRect,
65
9671
    f: F,
66
9671
    new_type: SurfaceType,
67
9671
) -> Result<SharedImageSurface, cairo::Error> {
68
9671
    let (width, height) = (surface.width(), surface.height());
69
9671
    let mut output_surface = ExclusiveImageSurface::new(width, height, new_type)?;
70
9671
    map_unpremultiplied_components_loop(surface, &mut output_surface, bounds, f);
71
9671

            
72
9671
    output_surface.share()
73
9671
}
74

            
75
/// Converts an sRGB surface to a linear sRGB surface (undoes the gamma correction).
76
#[inline]
77
5339
pub fn linearize_surface(
78
5339
    surface: &SharedImageSurface,
79
5339
    bounds: IRect,
80
5339
) -> Result<SharedImageSurface, cairo::Error> {
81
5339
    assert_eq!(surface.surface_type(), SurfaceType::SRgb);
82

            
83
5339
    map_unpremultiplied_components(surface, bounds, linearize, SurfaceType::LinearRgb)
84
5339
}
85

            
86
/// Converts a linear sRGB surface to a normal sRGB surface (applies the gamma correction).
87
#[inline]
88
4332
pub fn unlinearize_surface(
89
4332
    surface: &SharedImageSurface,
90
4332
    bounds: IRect,
91
4332
) -> Result<SharedImageSurface, cairo::Error> {
92
4332
    assert_eq!(surface.surface_type(), SurfaceType::LinearRgb);
93

            
94
4332
    map_unpremultiplied_components(surface, bounds, unlinearize, SurfaceType::SRgb)
95
4332
}