Remove the old node macro and fix/clean up several raster nodes (#2650)

* Fix several broken raster nodes and clean up leftover old node system code

* Migrate Brightness/Contrast to the new node macro, and fix it

* Remove last usages of old_node_fn

* Remove old_node_fn
This commit is contained in:
Keavon Chambers
2025-05-17 21:24:32 -07:00
committed by GitHub
parent 77f8bfd9ed
commit a8e209e44c
17 changed files with 511 additions and 1423 deletions

View File

@@ -585,16 +585,28 @@ impl<'i, N: for<'a> Node<'a, I> + Clone, I: 'i> Clone for TypeNode<N, I, <N as N
impl<'i, N: for<'a> Node<'a, I> + Copy, I: 'i> Copy for TypeNode<N, I, <N as Node<'i, I>>::Output> {}
// Into
pub struct IntoNode<O> {
_o: PhantomData<O>,
pub struct IntoNode<O>(PhantomData<O>);
impl<_O> IntoNode<_O> {
#[cfg(feature = "alloc")]
pub const fn new() -> Self {
Self(core::marker::PhantomData)
}
}
#[cfg(feature = "alloc")]
#[node_macro::old_node_fn(IntoNode<_O>)]
async fn into<I, _O>(input: I) -> _O
impl<_O> Default for IntoNode<_O> {
fn default() -> Self {
Self::new()
}
}
impl<'input, I: 'input, _O: 'input> Node<'input, I> for IntoNode<_O>
where
I: Into<_O> + Sync + Send,
{
input.into()
type Output = ::dyn_any::DynFuture<'input, _O>;
#[inline]
fn eval(&'input self, input: I) -> Self::Output {
Box::pin(async move { input.into() })
}
}
#[cfg(test)]

View File

@@ -14,8 +14,6 @@ use spirv_std::num_traits::float::Float;
pub mod adjustments;
pub mod bbox;
#[cfg(not(target_arch = "spirv"))]
pub mod brightness_contrast;
#[cfg(not(target_arch = "spirv"))]
pub mod brush_cache;
pub mod color;
#[cfg(not(target_arch = "spirv"))]

View File

@@ -1,7 +1,8 @@
#![allow(clippy::too_many_arguments)]
use crate::raster::curve::{CubicSplines, CurveManipulatorGroup};
#[cfg(feature = "alloc")]
use crate::raster::curve::{Curve, CurveManipulatorGroup, ValueMapperNode};
use crate::raster::curve::{Curve, ValueMapperNode};
#[cfg(feature = "alloc")]
use crate::raster::image::{Image, ImageFrameTable};
use crate::raster::{Channel, Color, Pixel};
@@ -326,10 +327,100 @@ fn make_opaque<T: Adjust<Color>>(
}
// Aims for interoperable compatibility with:
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27%20%3D%20Brightness/Contrast-,%27levl%27%20%3D%20Levels,-%27curv%27%20%3D%20Curves
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=%27brit%27%20%3D%20Brightness/Contrast
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=Padding-,Brightness%20and%20Contrast,-Key%20is%20%27brit
//
// Some further analysis available at:
// https://geraldbakker.nl/psnumbers/brightness-contrast.html
#[node_macro::node(name("Brightness/Contrast"), category("Raster: Adjustment"), properties("brightness_contrast_properties"))]
fn brightness_contrast<T: Adjust<Color>>(
_: impl Ctx,
#[implementations(
Color,
ImageFrameTable<Color>,
GradientStops,
)]
mut input: T,
brightness: SignedPercentage,
contrast: SignedPercentage,
use_classic: bool,
) -> T {
if use_classic {
let brightness = brightness as f32 / 255.;
let contrast = contrast as f32 / 100.;
let contrast = if contrast > 0. { (contrast * core::f32::consts::FRAC_PI_2 - 0.01).tan() } else { contrast };
let offset = brightness * contrast + brightness - contrast / 2.;
input.adjust(|color| color.to_gamma_srgb().map_rgb(|c| (c + c * contrast + offset).clamp(0., 1.)).to_linear_srgb());
return input;
}
const WINDOW_SIZE: usize = 1024;
// Brightness LUT
let brightness_is_negative = brightness < 0.;
// We clamp the brightness before the two curve X-axis points `130 - brightness * 26` and `233 - brightness * 48` intersect.
// Beyond the point of intersection, the cubic spline fitting becomes invalid and fails an assertion, which we need to avoid.
// See the intersection of the red lines at x = 103/22*100 = 468.18182 in the graph: https://www.desmos.com/calculator/ekvz4zyd9c
let brightness = (brightness.abs() / 100.).min(103. / 22. - 0.00001) as f32;
let brightness_curve_points = CubicSplines {
x: [0., 130. - brightness * 26., 233. - brightness * 48., 255.].map(|x| x / 255.),
y: [0., 130. + brightness * 51., 233. + brightness * 10., 255.].map(|x| x / 255.),
};
let brightness_curve_solutions = brightness_curve_points.solve();
let mut brightness_lut: [f32; WINDOW_SIZE] = core::array::from_fn(|i| {
let x = i as f32 / (WINDOW_SIZE as f32 - 1.);
brightness_curve_points.interpolate(x, &brightness_curve_solutions)
});
// Special handling for when brightness is negative
if brightness_is_negative {
brightness_lut = core::array::from_fn(|i| {
let mut x = i;
while x > 1 && brightness_lut[x] > i as f32 / WINDOW_SIZE as f32 {
x -= 1;
}
x as f32 / WINDOW_SIZE as f32
});
}
// Contrast LUT
// Unlike with brightness, the X-axis points `64` and `192` don't intersect at any contrast value, because they are constants.
// So we don't have to worry about clamping the contrast value to avoid invalid cubic spline fitting.
// See the graph: https://www.desmos.com/calculator/iql9vsca56
let contrast = contrast as f32 / 100.;
let contrast_curve_points = CubicSplines {
x: [0., 64., 192., 255.].map(|x| x / 255.),
y: [0., 64. - contrast * 30., 192. + contrast * 30., 255.].map(|x| x / 255.),
};
let contrast_curve_solutions = contrast_curve_points.solve();
let contrast_lut: [f32; WINDOW_SIZE] = core::array::from_fn(|i| {
let x = i as f32 / (WINDOW_SIZE as f32 - 1.);
contrast_curve_points.interpolate(x, &contrast_curve_solutions)
});
// Composed brightness and contrast LUTs
let combined_lut = brightness_lut.map(|brightness| {
let index_in_contrast_lut = (brightness * (contrast_lut.len() - 1) as f32).round() as usize;
contrast_lut[index_in_contrast_lut]
});
let lut_max = (combined_lut.len() - 1) as f32;
input.adjust(|color| color.to_gamma_srgb().map_rgb(|c| combined_lut[(c * lut_max).round() as usize]).to_linear_srgb());
input
}
// Aims for interoperable compatibility with:
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#:~:text=levl%27%20%3D%20Levels
//
// Algorithm from:
// https://stackoverflow.com/questions/39510072/algorithm-for-adjustment-of-image-levels
//
// Some further analysis available at:
// https://geraldbakker.nl/psnumbers/levels.html
#[node_macro::node(category("Raster: Adjustment"))]
fn levels<T: Adjust<Color>>(
_: impl Ctx,
@@ -748,7 +839,7 @@ async fn gradient_map<T: Adjust<Color>>(
image.adjust(|color| {
let intensity = color.luminance_srgb();
let intensity = if reverse { 1. - intensity } else { intensity };
gradient.evaluate(intensity as f64)
gradient.evaluate(intensity as f64).to_linear_srgb()
});
image
@@ -762,7 +853,7 @@ async fn gradient_map<T: Adjust<Color>>(
// https://stackoverflow.com/questions/33966121/what-is-the-algorithm-for-vibrance-filters
// The results of this implementation are very close to correct, but not quite perfect.
//
// A bit of additional analysis can be found at here:
// Some further analysis available at:
// https://www.photo-mark.com/notes/analyzing-photoshop-vibrance-and-saturation/
//
// This algorithm is currently lacking a "Saturation" parameter which is needed for interoperability.

View File

@@ -1,256 +0,0 @@
use crate::raster::curve::CubicSplines;
use crate::{Color, Node};
// LEGACY BRIGHTNESS/CONTRAST
pub struct BrightnessContrastLegacyMapperNode {
contrast: f32,
combined: f32,
}
impl<'i> Node<'i, Color> for BrightnessContrastLegacyMapperNode {
type Output = Color;
fn eval(&'i self, color: Color) -> Color {
let color = color.to_gamma_srgb();
let color = color.map_rgb(|c| (c + c * self.contrast + self.combined).clamp(0., 1.));
color.to_linear_srgb()
}
}
#[derive(Debug, Clone, Copy)]
pub struct GenerateBrightnessContrastLegacyMapperNode<Brightness, Contrast> {
brightness: Brightness,
contrast: Contrast,
}
#[node_macro::old_node_fn(GenerateBrightnessContrastLegacyMapperNode)]
fn brightness_contrast_legacy(_primary: (), brightness: f64, contrast: f64) -> BrightnessContrastLegacyMapperNode {
let brightness = brightness as f32 / 255.;
let contrast = contrast as f32 / 100.;
let contrast = if contrast > 0. { (contrast * core::f32::consts::FRAC_PI_2 - 0.01).tan() } else { contrast };
let combined = brightness * contrast + brightness - contrast / 2.;
BrightnessContrastLegacyMapperNode { contrast, combined }
}
// NORMAL BRIGHTNESS/CONTRAST
pub struct BrightnessContrastMapperNode {
combined_lut: [f32; WINDOW_SIZE],
}
impl<'i> Node<'i, Color> for BrightnessContrastMapperNode {
type Output = Color;
fn eval(&'i self, color: Color) -> Color {
let color = color.to_gamma_srgb();
let color = color.map_rgb(|c| {
let index_in_combined_lut = (c * (self.combined_lut.len() - 1) as f32).round() as usize;
self.combined_lut[index_in_combined_lut]
});
color.to_linear_srgb()
}
}
#[derive(Debug, Clone, Copy)]
pub struct GenerateBrightnessContrastMapperNode<Brightness, Contrast> {
brightness: Brightness,
contrast: Contrast,
}
// TODO: Replace this node implementation with one that reuses the more generalized Curves adjustment node.
// TODO: It will be necessary to ensure the tests below are faithfully translated in a way that ensures identical results.
#[node_macro::old_node_fn(GenerateBrightnessContrastMapperNode)]
fn brightness_contrast(_primary: (), brightness: f64, contrast: f64) -> BrightnessContrastMapperNode {
// Brightness LUT
let brightness_is_negative = brightness < 0.;
let brightness = brightness.abs() as f32 / 100.;
let brightness_curve_points = CubicSplines {
x: [0., 130. - brightness * 26., 233. - brightness * 48., 255.].map(|x| x / 255.),
y: [0., 130. + brightness * 51., 233. + brightness * 10., 255.].map(|x| x / 255.),
};
let brightness_curve_solutions = brightness_curve_points.solve();
let mut brightness_lut: [f32; WINDOW_SIZE] = core::array::from_fn(|i| {
let x = i as f32 / (WINDOW_SIZE as f32 - 1.);
brightness_curve_points.interpolate(x, &brightness_curve_solutions)
});
// Special handling for when brightness is negative
if brightness_is_negative {
brightness_lut = core::array::from_fn(|i| {
let mut x = i;
while x > 1 && brightness_lut[x] > i as f32 / WINDOW_SIZE as f32 {
x -= 1;
}
x as f32 / WINDOW_SIZE as f32
});
}
// Contrast LUT
let contrast = contrast as f32 / 100.;
let contrast_curve_points = CubicSplines {
x: [0., 64., 192., 255.].map(|x| x / 255.),
y: [0., 64. - contrast * 30., 192. + contrast * 30., 255.].map(|x| x / 255.),
};
let contrast_curve_solutions = contrast_curve_points.solve();
let contrast_lut: [f32; WINDOW_SIZE] = core::array::from_fn(|i| {
let x = i as f32 / (WINDOW_SIZE as f32 - 1.);
contrast_curve_points.interpolate(x, &contrast_curve_solutions)
});
// Composed brightness and contrast LUTs
let combined_lut = brightness_lut.map(|brightness| {
let index_in_contrast_lut = (brightness * (contrast_lut.len() - 1) as f32).round() as usize;
contrast_lut[index_in_contrast_lut]
});
BrightnessContrastMapperNode { combined_lut }
}
const WINDOW_SIZE: usize = 1024;
mod tests {
#[allow(unused_imports)]
use super::*;
#[allow(unused_imports)]
use crate::value::ClonedNode;
#[test]
fn brightness_contrast_legacy_tests() {
let string_data = |string: &str| string.split(',').map(|s| s.parse().unwrap()).collect::<Vec<u8>>();
let brightness_contrast_legacy_map = |brightness, contrast| -> [u8; 256] {
let brightness = ClonedNode::new(brightness);
let contrast = ClonedNode::new(contrast);
let generate_brightness_contrast_legacy_node = GenerateBrightnessContrastLegacyMapperNode::new(brightness, contrast);
let mapper = generate_brightness_contrast_legacy_node.eval(());
let color = |r| Color::from_rgbaf32_unchecked(r, 0., 0., 1.);
core::array::from_fn(|x| (mapper.eval(color(x as f32 / 255.)).r() * 255.).round() as u8)
};
assert_eq!(brightness_contrast_legacy_map(-150., 100.), [0; 256]);
assert_eq!(brightness_contrast_legacy_map(-77., 100.), {
let mut x = [0; 153].into_iter().chain([2, 20, 65, 143]).chain([255; 99]);
core::array::from_fn(|_| x.next().unwrap())
});
assert_eq!(brightness_contrast_legacy_map(0., 100.), {
let mut x = [0; 54].into_iter().chain([13, 107]).chain([255; 200]);
core::array::from_fn(|_| x.next().unwrap())
});
assert_eq!(brightness_contrast_legacy_map(53., 100.), {
let mut x = [0; 18].into_iter().chain([132]).chain([255; 237]);
core::array::from_fn(|_| x.next().unwrap())
});
assert_eq!(brightness_contrast_legacy_map(150., 100.), [255; 256]);
assert_eq!(
brightness_contrast_legacy_map(-150., 0.),
[0; 86].into_iter().chain(string_data("1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,6,6,6,6,6,6,6,7,7,7,7,7,8,8,8,8,8,8,9,9,9,9,9,10,10,10,10,10,11,11,11,11,11,12,12,12,12,13,13,13,13,13,14,14,14,14,15,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,24,24,24,25,25,25,25,26,26,26,27,27,27,27,28,28,28,29,29,29,30,30,30,30,31,31,31,32,32,32,33,33,33,33,34,34,34,35,35,35,36,36")).collect::<Vec<_>>().as_slice(),
);
assert_eq!(
brightness_contrast_legacy_map(-77., 0.),
string_data("0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,2,2,2,2,2,3,3,3,3,3,4,4,4,4,5,5,5,6,6,6,6,7,7,7,8,8,8,9,9,9,10,10,11,11,11,12,12,12,13,13,13,14,14,15,15,15,16,16,17,17,17,18,18,19,19,20,20,20,21,21,22,22,23,23,24,24,24,25,25,26,26,27,27,28,28,29,29,30,30,31,31,31,32,32,33,33,34,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,44,44,45,45,46,46,47,47,48,48,49,49,50,50,51,51,52,53,53,54,54,55,55,56,56,57,57,58,59,59,60,60,61,61,62,62,63,64,64,65,65,66,66,67,67,68,69,69,70,70,71,71,72,73,73,74,74,75,76,76,77,77,78,78,79,80,80,81,81,82,83,83,84,84,85,85,86,87,87,88,88,89,90,90,91,91,92,93,93,94,94,95,96,96,97,98,98,99,99,100,101,101,102,102,103,104,104,105,105,106,107,107,108,109,109,110,110,111,112,112,113,114").as_slice(),
);
assert_eq!(brightness_contrast_legacy_map(0., 0.), core::array::from_fn(|i| i as u8));
assert_eq!(
brightness_contrast_legacy_map(53., 0.),
string_data("9,14,18,21,24,27,29,32,34,37,39,41,43,45,47,49,51,53,55,57,59,61,63,65,66,68,70,72,73,75,77,79,80,82,84,85,87,89,90,92,94,95,97,99,100,102,104,105,107,108,110,111,113,115,116,118,119,121,122,124,126,127,129,130,132,133,135,136,138,139,141,142,144,145,147,148,150,151,153,154,156,157,159,160,161,163,164,166,167,169,170,172,173,175,176,177,179,180,182,183,185,186,187,189,190,192,193,195,196,197,199,200,202,203,204,206,207,209,210,211,213,214,216,217,218,220,221,223,224,225,227,228,230,231,232,234,235,236,238,239,241,242,243,245,246,247,249,250,251,253,254").into_iter().chain([255; 105]).collect::<Vec<_>>().as_slice(),
);
assert_eq!(
brightness_contrast_legacy_map(150., 0.),
string_data("78,93,105,114,122,129,135,141,147,152,157,162,167,171,176,180,184,188,192,196,200,204,208,211,215,218,222,225,229,232,236,239,242,245,249,252")
.into_iter()
.chain([255; 220])
.collect::<Vec<_>>()
.as_slice(),
);
assert_eq!(brightness_contrast_legacy_map(-150., -100.), [55; 256]);
assert_eq!(brightness_contrast_legacy_map(-77., -100.), [55; 256]);
assert_eq!(brightness_contrast_legacy_map(0., -100.), [55; 256]);
assert_eq!(brightness_contrast_legacy_map(53., -100.), [55; 256]);
assert_eq!(brightness_contrast_legacy_map(150., -100.), [55; 256]);
}
#[test]
fn brightness_contrast_tests() {
let string_data = |string: &str| string.split(',').map(|s| s.parse().unwrap()).collect::<Vec<u8>>();
let brightness_contrast_map = |brightness, contrast| -> [u8; 1024] {
let brightness = ClonedNode::new(brightness);
let contrast = ClonedNode::new(contrast);
let generate_brightness_contrast_node = GenerateBrightnessContrastMapperNode::new(brightness, contrast);
let mapper = generate_brightness_contrast_node.eval(());
let color = |r| Color::from_rgbaf32_unchecked(r, 0., 0., 1.);
core::array::from_fn(|x| (mapper.eval(color(x as f32 / 1023.)).r() * 255.).round() as u8)
};
assert_eq!(
&brightness_contrast_map(-150., 100.),
string_data("0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,29,29,29,29,29,29,30,30,30,30,30,30,30,30,31,31,31,31,31,31,32,32,32,32,33,33,33,33,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,36,36,37,37,37,37,38,38,38,38,39,39,39,39,40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43,44,44,44,44,45,45,45,45,46,46,47,47,47,47,48,48,49,49,49,49,50,50,50,50,51,51,52,52,52,53,53,53,53,54,54,55,55,56,56,57,57,57,57,58,58,59,59,60,60,61,61,61,62,62,63,63,64,64,65,65,67,67,68,68,69,69,70,70,72,72,72,73,73,74,74,76,76,77,77,79,79,81,81,82,82,82,84,84,86,86,88,88,90,90,92,92,94,94,94,97,97,99,99,101,101,104,104,107,107,110,110,110,113,113,116,116,119,119,123,123,126,126,126,130,130,133,133,137,137,141,141,145,145,145,149,149,154,154,158,158,163,163,163,168,168,172,172,177,177,182,182,182,188,188,193,193,198,198,204,204,204,209,209,215,215,220,220,226,226,226,232,232,237,237,243,243,249,249").as_slice()
);
assert_eq!(
brightness_contrast_map(-77., 100.),
string_data("0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,21,21,21,21,21,21,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,25,25,25,25,25,25,25,26,26,26,26,26,26,27,27,27,27,27,27,28,28,28,28,28,28,28,29,29,29,29,29,29,30,30,30,30,30,30,30,31,31,31,31,31,31,31,32,32,32,32,33,33,33,33,33,33,33,34,34,34,34,34,35,35,35,35,36,36,36,36,36,36,36,37,37,37,37,38,38,38,38,38,38,39,39,39,39,40,40,40,40,40,40,41,41,41,41,42,42,42,42,42,42,43,43,43,43,44,44,44,44,44,44,45,45,45,45,46,46,46,46,46,47,47,47,47,47,47,48,48,48,49,49,49,49,50,50,50,50,50,51,51,51,52,52,52,52,52,52,53,53,53,53,53,54,54,54,55,55,55,55,55,55,56,56,56,57,57,57,57,57,57,58,58,58,59,59,59,59,59,60,60,60,61,61,61,62,62,62,62,62,63,63,63,64,64,64,64,65,65,65,65,66,66,66,66,67,67,67,68,68,68,68,68,69,69,69,70,70,70,71,71,71,71,72,72,72,73,73,73,73,73,74,74,74,75,75,76,76,76,77,77,77,77,78,78,78,79,79,79,80,80,80,80,81,81,81,82,82,82,82,83,83,83,84,84,84,85,85,85,85,86,86,86,87,87,88,88,88,88,89,89,89,90,90,90,90,91,92,92,93,93,93,93,94,94,94,95,95,95,95,96,97,97,97,97,98,98,98,98,99,100,100,100,100,101,101,101,101,102,103,103,104,104,104,104,105,105,105,106,106,107,107,107,107,108,108,109,109,109,110,110,111,111,112,112,112,112,113,113,113,114,114,115,115,115,115,117,117,117,117,118,118,118,119,119,120,120,120,120,121,121,122,122,123,123,124,124,124,124,125,126,126,126,126,128,128,128,128,129,129,130,130,130,130,131,131,132,132,133,133,134,134,134,135,135,136,136,137,137,138,138,139,139,139,139,140,140,141,141,142,142,143,143,143,143,144,144,145,145,146,146,147,147,148,148,149,149,149,149,150,150,151,151,152,152,153,153,154,154,155,155,156,156,156,156,158,158,159,159,159,159,160,160,161,161,162,162,163,163,164,164,165,165,166,166,167,167,168,168,169,169,170,170,171,171,171,171,172,172,173,173,174,174,175,175,176,176,177,177,178,178,179,179,180,180,180,181,181,182,182,183,183,184,184,185,185,186,186,187,187,188,188,189,189,190,190,191,191,191,193,193,193,193,194,194,196,196,196,196,198,198,198,198,200,200,201,201,201,202,202,203,203,204,204,205,205,206,206,207,207,208,208,208,209,209,210,210,211,211,212,212,213,213,214,214,214,215,215,217,217,218,218,218,218,220,220,221,221,221,222,222,223,223,224,224,225,225,226,226,226,227,227,228,228,230,230,231,231,232,232,232,233,233,234,234,235,235,236,236,236,237,237,238,238,239,239,240,240,240,242,242,243,243,244,244,245,245,245,246,246,247,247,248,248,249,249,249,250,250,251,251,253,253,254,254").as_slice()
);
assert_eq!(
brightness_contrast_map(0., 100.),
string_data("0,0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,6,6,6,6,6,6,7,7,7,7,7,7,8,8,8,8,8,9,9,9,9,9,10,10,10,10,10,11,11,11,11,12,12,12,12,12,13,13,13,13,14,14,14,14,15,15,15,16,16,16,16,17,17,17,17,18,18,18,19,19,19,19,20,20,20,21,21,21,22,22,22,22,23,23,23,24,24,24,25,25,25,26,26,26,27,27,27,28,28,28,29,29,29,30,30,30,31,31,31,32,32,33,33,33,34,34,34,35,35,36,36,36,37,37,37,38,38,39,39,39,40,40,41,41,41,42,42,43,43,43,44,44,45,45,45,46,46,46,47,47,48,48,49,49,49,50,50,51,51,52,52,52,53,53,53,54,55,55,55,56,56,57,57,57,58,58,59,59,59,60,60,61,61,62,62,63,63,64,64,65,65,65,66,66,67,67,68,68,68,69,69,70,70,71,71,72,72,73,73,73,74,74,74,75,75,76,76,77,77,78,78,79,79,80,80,81,81,82,82,83,83,83,83,84,84,85,85,86,86,87,87,88,88,88,89,89,90,90,91,92,92,93,93,93,94,94,95,95,96,96,97,97,97,98,98,99,99,100,100,100,101,101,102,102,103,104,104,104,105,105,106,106,107,107,107,108,108,109,109,109,110,111,111,112,112,112,113,113,114,114,115,115,115,116,117,117,117,118,118,119,119,119,120,120,121,121,121,122,123,123,124,124,124,125,125,126,126,126,127,128,128,128,129,129,130,130,130,131,131,131,132,133,133,133,134,134,135,135,135,136,137,137,137,138,138,139,139,139,140,140,140,141,142,142,142,143,143,144,144,144,145,145,145,146,147,147,147,148,148,148,149,149,149,150,150,151,151,152,152,153,153,153,154,154,154,155,155,155,156,156,156,157,158,158,158,159,159,159,160,160,160,161,161,161,162,162,163,163,163,164,164,165,165,165,166,166,166,167,167,168,168,168,169,169,169,170,170,170,171,171,171,172,172,172,173,173,173,174,174,174,175,175,175,176,176,176,177,177,177,178,178,178,179,179,179,180,180,180,180,181,181,181,182,182,182,183,183,183,184,184,184,185,185,185,186,186,186,187,187,187,188,188,188,188,188,189,189,189,190,190,190,191,191,191,191,192,192,192,193,193,193,193,193,194,194,194,195,195,195,196,196,196,196,196,197,197,197,198,198,198,198,198,199,199,199,200,200,200,200,201,201,201,201,201,202,202,202,203,203,203,203,203,204,204,204,204,204,205,205,205,206,206,206,206,206,207,207,207,207,208,208,208,208,208,209,209,209,209,209,210,210,210,210,210,211,211,211,211,211,212,212,212,212,213,213,213,213,213,214,214,214,214,214,215,215,215,215,215,215,216,216,216,216,216,217,217,217,217,217,218,218,218,218,218,218,218,219,219,219,219,219,219,220,220,220,220,220,221,221,221,221,221,221,222,222,222,222,222,222,222,223,223,223,223,223,224,224,224,224,224,224,224,224,225,225,225,225,225,226,226,226,226,226,226,226,226,227,227,227,227,227,227,227,228,228,228,228,228,228,229,229,229,229,229,229,229,230,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,233,234,234,234,234,234,234,234,234,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(53., 100.),
string_data("0,0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,3,3,3,3,3,4,4,4,4,5,5,5,6,6,6,7,7,7,8,8,8,9,9,10,10,11,11,12,12,12,13,13,14,15,15,16,16,17,17,18,19,19,19,20,21,22,22,23,23,24,25,25,26,27,27,28,29,29,30,31,31,32,33,34,34,35,36,36,37,38,39,40,40,41,42,43,43,44,45,46,46,47,48,49,50,50,51,52,53,53,55,55,56,57,57,59,59,60,61,62,63,63,65,65,66,67,68,68,69,70,71,72,73,73,74,75,76,77,77,79,79,80,81,82,83,83,84,85,86,86,87,88,89,90,90,92,93,93,94,95,96,96,98,98,99,99,101,101,102,102,104,105,105,106,107,108,108,109,110,111,112,112,113,114,115,115,116,117,118,119,119,120,120,121,123,123,124,124,125,126,126,128,128,129,129,130,131,131,132,133,134,135,135,136,137,137,138,138,139,140,141,142,142,143,143,144,145,145,146,147,147,148,148,149,149,150,152,152,153,153,154,154,155,155,156,157,158,158,159,159,160,160,161,161,162,162,163,164,165,165,166,166,167,167,168,168,168,169,169,170,170,171,171,172,173,173,174,174,175,175,176,176,177,177,177,178,178,179,179,180,180,181,181,182,182,183,183,183,184,184,185,185,186,186,187,187,187,188,188,188,189,189,190,190,191,191,191,192,192,193,193,193,193,194,194,195,195,196,196,196,196,197,197,198,198,198,198,199,199,200,200,201,201,201,201,201,202,202,202,203,203,203,204,204,204,204,205,205,206,206,206,206,207,207,207,207,208,208,208,208,209,209,209,210,210,210,210,210,211,211,211,211,212,212,212,213,213,213,213,213,214,214,214,214,215,215,215,215,216,216,216,216,216,217,217,217,217,218,218,218,218,218,218,218,219,219,219,219,219,220,220,220,220,221,221,221,221,221,221,222,222,222,222,222,222,222,223,223,223,223,224,224,224,224,224,224,224,225,225,225,225,225,226,226,226,226,226,226,226,227,227,227,227,227,227,227,227,228,228,228,228,228,229,229,229,229,229,229,229,229,229,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,233,234,234,234,234,234,234,234,234,234,234,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,240,240,240,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(150., 100.),
string_data("0,0,0,1,1,1,2,2,3,4,5,6,7,9,10,12,14,16,18,20,22,25,28,30,33,36,38,41,44,47,50,53,56,59,62,65,68,71,74,77,81,84,87,90,94,96,99,102,105,108,112,114,117,119,123,125,128,130,133,135,138,140,143,146,148,150,152,154,157,159,161,163,165,167,169,170,172,174,176,177,179,181,182,184,186,187,188,189,191,192,193,195,196,197,198,199,200,201,202,203,204,205,206,207,208,209,209,210,211,211,213,214,214,215,215,216,216,217,218,218,219,219,220,221,221,222,222,222,223,224,224,224,225,225,226,226,226,227,227,228,228,228,229,229,230,230,230,231,231,231,232,232,232,232,233,233,233,233,233,234,234,234,235,235,235,235,236,236,236,236,236,237,237,237,237,238,238,238,238,238,238,239,239,239,239,239,239,239,240,240,240,240,240,240,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(-150., 0.),
string_data("0,0,0,0,0,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,42,42,42,42,42,42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,45,45,45,45,45,45,46,46,46,46,46,46,47,47,47,47,47,47,48,48,48,48,48,48,49,49,49,49,50,50,50,50,50,50,51,51,51,51,52,52,52,52,52,52,53,53,53,53,53,54,54,54,54,54,54,55,55,55,55,56,56,56,56,57,57,57,57,58,58,58,58,58,59,59,60,60,60,60,61,61,62,62,62,62,63,63,64,64,64,64,64,65,65,66,66,67,67,67,67,69,69,69,69,70,70,70,71,71,72,72,73,73,74,74,76,76,77,77,77,78,78,79,79,81,81,82,82,84,84,85,85,85,87,87,89,89,91,91,92,92,94,94,94,97,97,99,99,101,101,103,103,106,106,106,108,108,111,111,114,114,117,117,117,120,120,124,124,127,127,131,131,131,135,135,140,140,145,145,151,151,151,157,157,164,164,172,172,180,180,180,191,191,203,203,218,218,235,235").as_slice()
);
assert_eq!(
brightness_contrast_map(-77., 0.),
string_data("0,0,0,0,1,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,60,60,60,60,60,60,61,61,61,61,61,61,61,62,62,62,62,62,62,63,63,63,63,63,63,63,64,64,64,64,64,64,65,65,65,65,65,65,65,66,66,66,66,66,67,67,67,67,67,67,67,68,68,68,68,68,69,69,69,69,69,69,70,70,70,70,70,70,71,71,71,71,71,71,72,72,72,72,72,72,73,73,73,73,73,74,74,74,74,74,74,74,75,75,75,75,75,76,76,76,76,76,77,77,77,77,77,77,78,78,78,78,78,79,79,79,79,79,80,80,80,80,80,80,81,81,81,82,82,82,82,82,82,82,82,83,83,83,84,84,84,84,84,84,85,85,85,85,85,86,86,86,86,87,87,87,87,87,88,88,88,88,88,88,89,89,89,89,90,90,90,91,91,91,91,91,91,92,92,92,92,92,92,93,93,93,93,94,94,94,95,95,95,95,96,96,96,96,97,97,97,97,98,98,98,98,98,98,99,99,99,100,100,100,100,101,101,101,101,102,102,102,102,103,103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107,107,107,107,108,108,108,108,109,109,109,109,110,110,111,111,111,111,112,112,112,112,113,113,113,113,114,114,115,115,115,115,116,116,116,116,117,117,118,118,119,119,119,119,120,120,120,120,121,121,122,122,123,123,123,123,124,124,124,124,125,125,126,126,127,127,127,127,128,128,129,129,130,130,130,130,130,131,131,132,132,133,133,134,134,134,134,135,135,136,136,137,137,138,138,139,139,139,140,140,141,141,141,141,143,143,143,143,145,145,145,145,147,147,148,148,148,149,149,150,150,151,151,152,152,153,153,154,154,156,156,156,157,157,158,158,159,159,161,161,162,162,163,163,163,165,165,166,166,168,168,169,169,171,171,172,172,172,174,174,176,176,177,177,179,179,181,181,181,183,183,185,185,187,187,189,189,191,191,191,193,193,196,196,198,198,200,200,200,202,202,205,205,208,208,210,210,210,213,213,216,216,219,219,222,222,222,225,225,229,229,232,232,236,236,236,239,239,243,243,247,247,250,250").as_slice()
);
assert_eq!(
brightness_contrast_map(0., 0.),
string_data("0,0,1,1,1,1,2,2,2,2,3,3,3,3,3,4,4,4,4,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,8,9,9,9,9,10,10,10,10,11,11,11,11,12,12,12,13,13,13,13,14,14,14,14,14,15,15,15,15,16,16,16,16,17,17,17,17,18,18,18,18,19,19,19,19,20,20,20,20,21,21,21,21,22,22,22,22,23,23,23,23,24,24,24,24,25,25,25,25,26,26,26,26,27,27,27,27,28,28,28,28,29,29,29,29,30,30,30,30,31,31,31,31,32,32,32,32,33,33,33,33,34,34,34,34,35,35,35,35,36,36,36,36,37,37,37,37,38,38,38,38,39,39,39,39,40,40,40,40,41,41,41,41,42,42,42,42,43,43,43,43,44,44,44,44,45,45,45,45,46,46,46,46,47,47,47,47,48,48,48,48,49,49,49,49,50,50,50,50,51,51,51,51,52,52,52,52,53,53,53,53,54,54,54,54,55,55,55,55,56,56,56,56,57,57,57,57,58,58,58,58,58,59,59,59,60,60,60,60,61,61,61,61,62,62,62,62,63,63,63,63,64,64,64,64,65,65,65,65,66,66,66,66,66,67,67,67,67,68,68,68,69,69,69,69,70,70,70,70,71,71,71,71,71,72,72,72,73,73,73,73,74,74,74,74,74,75,75,75,76,76,76,76,76,77,77,77,78,78,78,78,78,79,79,79,80,80,80,80,80,81,81,81,82,82,82,82,82,83,83,83,84,84,84,84,85,85,85,85,85,86,86,86,87,87,87,87,88,88,88,88,88,89,89,89,89,90,90,90,91,91,91,91,92,92,92,92,92,93,93,93,93,94,94,94,94,95,95,95,95,96,96,96,97,97,97,97,98,98,98,98,99,99,99,99,100,100,100,100,101,101,101,101,102,102,102,102,103,103,103,103,104,104,104,104,105,105,105,105,106,106,106,106,107,107,107,107,108,108,108,108,108,109,109,109,109,110,110,110,110,111,111,111,111,112,112,112,112,113,113,113,113,113,114,114,115,115,115,115,115,116,116,116,116,117,117,117,117,118,118,118,119,119,119,119,119,120,120,120,120,121,121,121,121,122,122,122,123,123,123,123,123,124,124,124,124,125,125,125,126,126,126,126,126,127,127,127,127,128,128,128,129,129,129,129,129,130,130,130,130,130,131,131,131,132,132,132,132,133,133,133,134,134,134,134,134,135,135,135,135,135,136,136,136,137,137,137,137,137,138,138,138,139,139,139,139,139,140,140,140,141,141,141,141,141,142,142,142,143,143,143,143,143,144,144,144,145,145,145,145,145,146,146,146,147,147,147,147,148,148,148,148,148,149,149,149,150,150,150,150,150,151,151,151,152,152,152,152,153,153,153,153,153,154,154,154,155,155,155,156,156,156,156,156,156,157,157,157,158,158,158,158,158,159,159,159,159,160,160,160,161,161,161,161,162,162,162,162,162,163,163,163,164,164,164,164,165,165,165,165,165,166,166,166,166,167,167,167,168,168,168,168,169,169,169,169,169,170,170,170,170,171,171,171,172,172,172,172,173,173,173,173,173,174,174,174,174,175,175,175,175,176,176,176,177,177,177,177,178,178,178,178,179,179,179,179,179,180,180,180,180,181,181,181,181,182,182,182,183,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,186,187,187,187,187,188,188,188,188,189,189,189,189,190,190,190,190,191,191,191,191,192,192,192,193,193,193,193,194,194,194,194,195,195,195,195,196,196,196,196,197,197,197,197,198,198,198,198,198,198,199,199,199,199,200,200,200,200,201,201,201,201,202,202,202,202,203,203,203,203,204,204,204,204,205,205,205,205,206,206,206,206,207,207,207,207,208,208,208,208,209,209,209,209,210,210,210,210,211,211,211,211,212,212,212,212,213,213,213,213,214,214,215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,218,219,219,219,219,220,220,220,220,221,221,221,221,222,222,222,222,223,223,223,223,223,224,224,224,224,225,225,225,225,226,226,227,227,227,227,228,228,228,228,228,229,229,229,229,230,230,230,230,231,231,231,231,232,232,232,232,232,233,233,233,233,234,234,235,235,235,235,235,236,236,236,236,237,237,237,237,238,238,238,238,238,239,239,239,239,240,240,241,241,241,241,241,242,242,242,242,243,243,243,243,244,244,244,244,244,245,245,245,245,246,246,246,247,247,247,247,248,248,248,248,248,249,249,249,249,250,250,250,250,250,251,251,252,252,252,252,253,253,253,253,253,254,254,254,254,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(53., 0.),
string_data("0,0,1,1,2,2,3,3,4,4,5,5,6,6,6,7,8,8,9,9,10,10,11,11,12,12,13,13,14,14,15,15,16,16,17,17,18,18,19,19,20,20,21,21,22,22,23,24,24,24,25,25,26,27,27,28,28,29,29,29,30,31,31,32,32,33,33,33,34,35,35,36,36,37,37,38,38,39,39,40,40,41,41,42,42,43,43,43,44,44,45,45,46,46,47,48,48,48,49,50,50,50,51,51,52,52,53,53,54,54,55,55,56,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63,63,64,64,65,65,66,66,67,67,67,68,69,69,70,70,71,71,71,72,72,73,73,74,74,74,75,75,76,76,76,77,78,78,79,79,79,80,80,81,81,81,82,82,83,83,84,84,85,85,85,86,86,87,87,88,88,88,89,89,90,90,91,91,91,92,92,93,93,93,94,94,95,95,96,96,96,97,97,98,98,99,99,100,100,100,101,101,101,102,102,103,103,104,104,104,105,105,106,106,106,107,107,107,108,108,108,109,110,110,110,111,111,111,112,112,113,113,113,114,114,115,115,115,116,116,116,117,117,118,118,119,119,119,120,120,120,120,121,121,121,122,122,123,123,123,124,124,125,125,126,126,126,127,127,127,127,128,128,129,129,129,130,130,130,131,131,132,132,132,132,133,133,134,134,134,135,135,135,135,136,136,137,137,137,138,138,138,139,139,139,140,140,141,141,141,141,142,142,143,143,143,143,144,144,145,145,145,145,146,146,147,147,148,148,148,148,148,149,149,149,150,150,150,151,151,151,152,152,153,153,153,153,154,154,154,154,155,155,156,156,156,156,157,157,158,158,158,158,158,159,159,159,160,160,160,161,161,162,162,162,162,162,163,163,163,164,164,164,165,165,165,165,165,166,166,167,167,167,168,168,168,168,169,169,169,169,170,170,170,170,171,171,171,172,172,172,173,173,173,173,173,174,174,174,175,175,175,175,176,176,176,177,177,177,177,178,178,178,179,179,179,179,179,180,180,180,180,180,181,181,182,182,182,182,182,183,183,183,184,184,184,184,185,185,185,185,186,186,186,186,186,186,187,187,187,188,188,188,188,189,189,189,189,189,190,190,190,191,191,191,191,192,192,192,192,192,193,193,193,193,194,194,194,194,194,195,195,195,196,196,196,196,196,197,197,197,197,198,198,198,198,198,198,198,198,199,199,199,199,199,200,200,200,200,201,201,201,201,201,202,202,202,202,202,203,203,203,203,203,204,204,204,204,205,205,205,205,205,206,206,206,206,206,206,206,207,207,207,207,208,208,208,208,208,209,209,209,209,209,210,210,210,210,210,210,210,211,211,211,211,211,212,212,212,212,212,212,212,213,213,213,213,213,214,214,214,215,215,215,215,215,215,215,216,216,216,216,216,216,216,217,217,217,217,217,218,218,218,218,218,218,218,219,219,219,219,219,219,219,220,220,220,220,220,220,220,221,221,221,221,221,221,221,222,222,222,222,222,222,222,223,223,223,223,223,223,223,223,223,224,224,224,224,224,224,224,225,225,225,225,225,225,225,226,226,226,226,226,227,227,227,227,227,227,227,227,228,228,228,228,228,228,228,228,228,229,229,229,229,229,229,229,229,229,230,230,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,233,234,234,234,234,234,234,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(150., 0.),
string_data("0,1,2,3,4,6,8,9,11,13,15,16,18,20,22,24,26,28,29,32,33,35,37,39,41,43,44,46,48,50,52,54,56,57,59,61,62,64,66,67,69,71,73,75,76,78,80,81,82,85,86,88,89,91,92,94,95,97,98,100,102,103,104,106,107,109,110,111,113,115,116,117,119,120,121,122,124,125,126,127,129,130,131,133,134,135,136,137,138,139,141,142,143,144,145,146,147,148,149,150,151,153,153,154,156,156,157,158,159,160,161,162,163,164,165,165,166,167,168,169,170,170,171,172,173,173,174,175,176,177,178,178,179,179,180,181,181,182,183,184,184,185,186,186,187,187,188,189,189,190,191,191,191,192,193,193,194,195,195,196,196,197,197,198,198,198,199,199,200,200,201,201,202,202,203,203,203,204,204,205,205,206,206,207,207,207,208,208,209,209,209,209,210,210,211,211,211,212,212,212,212,213,213,214,214,215,215,215,215,216,216,217,217,217,217,218,218,218,218,219,219,219,220,220,220,220,220,221,221,221,221,222,222,222,222,222,223,223,223,223,224,224,224,224,224,225,225,225,225,225,226,226,226,227,227,227,227,227,228,228,228,228,228,228,229,229,229,229,229,229,229,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,234,234,234,234,234,235,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(-150., -100.),
string_data("0,0,0,0,1,1,1,1,1,1,1,1,1,2,2,2,2,2,2,2,2,2,2,3,3,3,3,3,3,3,3,3,3,4,4,4,4,4,4,4,4,4,4,4,4,5,5,5,5,5,5,5,5,5,5,6,6,6,6,6,6,6,6,6,6,6,6,7,7,7,7,7,7,7,7,7,7,7,8,8,8,8,8,8,8,8,8,8,8,8,9,9,9,9,9,9,9,9,9,9,9,9,10,10,10,10,10,10,10,10,10,10,10,10,11,11,11,11,11,11,11,11,11,11,11,11,12,12,12,12,12,12,12,12,12,12,12,12,12,13,13,13,13,13,13,13,13,13,13,13,13,13,14,14,14,14,14,14,14,14,14,14,14,15,15,15,15,15,15,15,15,15,15,15,15,15,15,16,16,16,16,16,16,16,16,16,16,16,16,16,16,17,17,17,17,17,17,17,17,17,17,17,17,18,18,18,18,18,18,18,18,18,18,18,18,18,19,19,19,19,19,19,19,19,19,19,19,19,19,20,20,20,20,20,20,20,20,20,20,20,20,20,20,20,21,21,21,21,21,21,21,21,21,21,21,21,21,21,22,22,22,22,22,22,22,22,22,22,22,22,22,22,23,23,23,23,23,23,23,23,23,23,23,23,23,23,23,24,24,24,24,24,24,24,24,24,24,24,24,24,24,25,25,25,25,25,25,25,25,25,25,25,25,25,25,25,26,26,26,26,26,26,26,26,26,26,26,26,26,26,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,28,28,28,28,28,28,28,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,61,61,61,61,61,61,61,62,62,62,62,63,63,63,63,64,64,64,64,64,65,65,66,66,66,66,67,67,68,68,68,69,69,70,70,71,71,72,72,73,73,73,75,75,76,76,78,78,80,80,80,82,82,84,84,87,87,90,90,90,93,93,97,97,101,101,107,107,107,113,113,121,121,130,130,141,141,141,154,154,172,172,194,194,222,222").as_slice()
);
assert_eq!(
brightness_contrast_map(-77., -100.),
string_data("0,0,0,1,1,1,1,2,2,2,2,3,3,3,3,4,4,4,4,5,5,5,5,6,6,6,6,6,7,7,7,7,8,8,8,8,8,9,9,9,9,10,10,10,10,10,11,11,11,11,12,12,12,12,12,13,13,13,13,13,14,14,14,14,15,15,15,15,15,16,16,16,16,16,16,17,17,17,17,17,18,18,18,18,18,19,19,19,19,19,20,20,20,20,20,20,20,21,21,21,21,21,22,22,22,22,22,22,23,23,23,23,23,24,24,24,24,24,24,24,25,25,25,25,25,25,26,26,26,26,26,26,27,27,27,27,27,27,27,28,28,28,28,28,28,28,28,29,29,29,29,29,29,30,30,30,30,30,30,30,30,30,31,31,31,31,31,31,31,32,32,32,32,32,32,32,32,33,33,33,33,33,33,33,33,33,34,34,34,34,34,34,34,34,35,35,35,35,35,35,35,35,35,36,36,36,36,36,36,36,36,36,36,36,37,37,37,37,37,37,37,37,37,38,38,38,38,38,38,38,38,38,38,38,38,39,39,39,39,39,39,39,39,39,39,40,40,40,40,40,40,40,40,40,40,40,40,40,41,41,41,41,41,41,41,41,41,41,41,41,42,42,42,42,42,42,42,42,42,42,42,42,42,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,44,44,44,44,44,44,44,44,44,44,44,44,44,44,45,45,45,45,45,45,45,45,45,45,45,45,45,45,45,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70,70,70,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,73,73,73,73,73,73,73,73,74,74,74,74,74,74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,77,77,77,77,77,77,78,78,78,78,78,78,79,79,79,79,79,79,80,80,80,80,81,81,81,81,81,81,82,82,82,82,83,83,83,83,84,84,84,84,85,85,85,85,86,86,86,86,87,87,87,87,88,88,88,88,88,89,89,90,90,90,90,91,91,91,91,92,92,93,93,94,94,94,94,95,95,96,96,96,97,97,97,97,98,98,99,99,100,100,101,101,102,102,103,103,104,104,104,105,105,106,106,107,107,108,108,109,109,110,110,112,112,112,113,113,114,114,116,116,117,117,119,119,120,120,120,122,122,124,124,125,125,127,127,129,129,131,131,131,133,133,135,135,137,137,139,139,141,141,141,144,144,146,146,149,149,152,152,154,154,154,158,158,161,161,164,164,167,167,167,171,171,175,175,179,179,183,183,183,187,187,191,191,196,196,201,201,201,206,206,212,212,217,217,222,222,222,229,229,234,234,241,241,247,247").as_slice()
);
assert_eq!(
brightness_contrast_map(0., -100.),
string_data("0,0,1,1,2,3,3,4,5,5,6,7,7,8,8,9,10,10,11,12,12,13,13,14,15,15,16,16,17,17,18,19,19,20,20,21,21,22,22,23,23,24,24,25,25,25,26,26,27,27,28,28,28,29,29,30,30,30,31,31,31,32,32,32,33,33,33,34,34,34,35,35,35,35,36,36,36,36,37,37,37,38,38,38,38,39,39,39,39,39,40,40,40,40,40,41,41,41,41,42,42,42,42,42,42,43,43,43,43,43,43,44,44,44,44,44,44,45,45,45,45,45,45,45,46,46,46,46,46,46,46,47,47,47,47,47,47,47,47,48,48,48,48,48,48,48,48,49,49,49,49,49,49,49,49,49,49,50,50,50,50,50,50,50,50,50,50,51,51,51,51,51,51,51,51,51,51,51,52,52,52,52,52,52,52,52,52,52,52,52,53,53,53,53,53,53,53,53,53,53,53,53,53,54,54,54,54,54,54,54,54,54,54,54,54,54,55,55,55,55,55,55,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,56,56,56,56,56,56,57,57,57,57,57,57,57,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,60,60,60,60,60,61,61,61,61,61,61,61,61,61,61,61,61,62,62,62,62,62,62,62,62,62,62,62,63,63,63,63,63,63,63,63,63,63,63,63,64,64,64,64,64,64,64,64,64,64,64,65,65,65,65,65,65,65,65,65,65,65,66,66,66,66,66,66,66,66,66,66,67,67,67,67,67,67,67,67,67,67,68,68,68,68,68,68,68,68,68,69,69,69,69,69,69,69,69,69,70,70,70,70,70,70,70,70,70,71,71,71,71,71,71,71,71,72,72,72,72,72,72,72,72,73,73,73,73,73,73,73,73,74,74,74,74,74,74,74,75,75,75,75,75,75,75,75,76,76,76,76,76,76,76,77,77,77,77,77,77,77,78,78,78,78,78,78,78,79,79,79,79,79,79,80,80,80,80,80,80,80,81,81,81,81,81,81,82,82,82,82,82,82,83,83,83,83,83,83,84,84,84,84,84,84,85,85,85,85,85,85,86,86,86,86,86,86,87,87,87,87,88,88,88,88,88,88,88,89,89,89,89,90,90,90,90,90,91,91,91,91,91,91,92,92,92,92,92,93,93,93,93,94,94,94,94,94,95,95,95,95,95,96,96,96,96,96,97,97,97,97,97,98,98,98,98,99,99,99,99,100,100,100,100,101,101,101,101,101,102,102,102,102,103,103,103,103,103,104,104,104,105,105,105,105,105,106,106,106,107,107,107,107,107,108,108,108,108,109,109,109,110,110,110,110,110,111,111,111,112,112,112,112,113,113,113,114,114,114,114,114,115,115,115,115,116,116,116,117,117,117,117,118,118,118,119,119,119,119,120,120,120,121,121,121,121,122,122,122,123,123,123,123,124,124,124,125,125,125,125,126,126,126,126,127,127,127,128,128,128,128,129,129,129,130,130,131,131,131,131,132,132,132,133,133,133,133,134,134,134,134,135,135,136,136,136,137,137,137,137,138,138,138,138,139,140,140,140,140,141,141,141,141,142,142,143,143,143,144,144,144,144,145,145,146,146,146,146,147,147,147,147,148,148,149,149,149,150,150,151,151,151,151,152,152,152,152,153,153,154,154,154,154,155,155,156,156,156,157,157,158,158,158,158,159,159,160,160,160,160,161,161,162,162,162,162,163,163,164,164,165,165,165,165,166,166,167,167,167,167,168,168,169,169,169,169,170,170,171,171,172,172,172,172,173,173,174,174,175,175,175,175,176,176,177,177,178,178,178,178,179,179,180,180,181,181,181,181,182,182,183,183,184,184,184,184,185,185,186,186,187,187,187,187,188,188,189,189,190,190,191,191,191,191,192,192,193,193,194,194,194,195,195,195,195,196,196,197,197,198,198,199,199,199,199,200,200,201,201,202,202,203,203,203,204,204,204,204,205,205,206,206,207,207,208,208,209,209,209,209,210,210,210,211,211,212,212,213,213,214,214,215,215,215,215,216,216,216,217,217,218,218,219,219,220,220,221,221,222,222,222,222,222,223,223,224,224,225,225,226,226,227,227,227,228,228,229,229,230,230,231,231,231,231,231,232,232,233,233,234,234,235,235,236,236,236,237,237,238,238,239,239,240,240,240,241,241,242,242,243,243,244,244,244,244,244,245,245,246,246,247,247,247,248,248,249,249,250,250,251,251,251,252,252,253,253,254,254,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(53., -100.),
string_data("0,1,1,2,3,5,6,7,9,10,11,12,13,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30,30,31,32,33,33,34,34,35,36,36,37,37,38,38,39,39,40,40,41,41,41,42,42,43,43,43,44,44,44,44,45,45,45,46,46,46,47,47,47,47,48,48,48,48,48,49,49,49,49,50,50,50,50,50,51,51,51,51,51,51,52,52,52,52,52,52,53,53,53,53,53,53,53,54,54,54,54,54,54,55,55,55,55,55,55,55,55,56,56,56,56,56,56,56,57,57,57,57,57,57,57,58,58,58,58,58,58,58,58,59,59,59,59,59,59,59,60,60,60,60,60,60,60,60,61,61,61,61,61,61,62,62,62,62,62,62,62,63,63,63,63,63,63,63,64,64,64,64,64,64,65,65,65,65,65,65,66,66,66,66,66,66,67,67,67,67,67,67,68,68,68,68,68,69,69,69,69,69,69,70,70,70,70,70,71,71,71,71,71,71,72,72,72,72,73,73,73,73,73,74,74,74,74,74,75,75,75,75,76,76,76,76,76,77,77,77,77,78,78,78,78,78,79,79,79,79,80,80,80,80,81,81,81,81,82,82,82,82,82,83,83,83,83,84,84,84,85,85,85,85,86,86,86,86,87,87,87,87,88,88,88,88,89,89,89,90,90,90,90,91,91,91,91,92,92,92,93,93,93,93,94,94,94,95,95,95,95,96,96,96,97,97,97,97,98,98,98,99,99,100,100,100,100,101,101,101,102,102,102,103,103,103,104,104,104,104,105,105,105,105,106,106,107,107,107,107,108,108,109,109,109,110,110,110,110,110,111,111,112,112,112,113,113,114,114,114,114,115,115,115,115,116,116,117,117,117,118,118,119,119,119,119,120,120,120,121,121,121,122,122,122,123,123,123,124,124,124,125,125,125,125,126,126,127,127,127,128,128,128,128,129,129,129,130,131,131,131,131,132,132,132,133,133,133,134,134,134,134,135,136,136,136,136,137,137,137,138,138,138,138,139,139,140,140,140,141,141,141,141,142,143,143,143,143,143,144,144,144,145,145,146,146,146,147,147,147,147,147,148,149,149,149,149,150,150,151,151,151,151,152,152,152,152,152,153,154,154,154,154,154,155,156,156,156,156,156,157,158,158,158,158,158,159,159,159,160,160,160,161,161,161,162,162,162,162,162,163,164,164,164,165,165,165,165,165,166,167,167,167,167,167,168,168,168,169,169,169,169,169,170,170,171,171,171,172,172,172,172,172,173,173,173,174,175,175,175,175,175,176,176,176,177,177,177,177,178,178,178,178,179,179,180,180,180,181,181,181,181,181,182,182,182,182,183,183,183,184,184,184,184,184,185,185,185,186,186,186,186,187,187,187,187,187,188,188,188,189,189,189,190,190,190,190,191,191,191,191,191,191,191,192,193,193,193,193,194,194,194,195,195,195,195,195,195,195,196,196,196,196,197,197,197,198,198,198,198,199,199,199,199,199,199,199,200,200,200,201,201,201,201,202,202,202,203,203,203,203,203,203,204,204,204,204,204,204,204,205,205,205,206,206,206,206,207,207,207,207,207,208,208,208,208,209,209,209,209,209,209,209,209,209,210,210,210,210,211,211,211,211,212,212,212,212,212,213,213,213,213,214,214,214,214,214,215,215,215,215,215,215,215,215,215,215,216,216,216,216,217,217,217,217,217,218,218,218,218,219,219,219,219,219,219,220,220,220,220,220,220,221,221,221,222,222,222,222,222,222,222,222,222,222,222,222,223,223,223,223,223,223,224,224,224,224,225,225,225,225,225,225,226,226,226,226,226,226,227,227,227,227,227,227,228,228,228,228,228,228,229,229,229,229,229,229,230,230,230,230,230,230,231,231,231,231,231,231,231,231,231,231,231,231,232,232,232,232,232,232,233,233,233,233,233,233,233,233,234,234,234,234,234,234,235,235,235,235,235,235,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,239,239,239,239,239,239,240,240,240,240,240,240,240,240,240,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,255,255,255,255").as_slice()
);
assert_eq!(
brightness_contrast_map(150., -100.),
string_data("0,1,3,6,10,14,18,22,25,28,31,33,36,38,39,41,42,44,45,46,47,48,49,50,50,51,51,52,53,53,54,54,55,56,56,57,57,58,58,59,59,60,60,61,61,62,62,63,63,64,65,65,66,66,67,68,68,69,70,70,71,72,73,74,74,75,76,76,77,78,79,80,81,81,82,83,84,85,86,87,88,89,90,91,92,93,93,94,95,96,97,98,99,100,101,103,103,104,105,107,107,109,110,110,112,113,114,114,116,116,118,119,120,121,122,123,123,125,126,126,128,128,129,131,132,132,133,134,136,136,137,138,139,140,140,141,142,143,144,145,146,146,147,148,149,150,151,152,152,153,154,155,155,156,157,158,159,160,160,161,162,162,163,164,165,165,166,167,167,168,169,169,170,170,172,172,172,173,174,175,175,176,176,178,178,178,179,179,181,181,181,181,182,183,184,184,184,185,185,186,186,187,187,188,188,189,189,190,190,191,191,192,192,193,193,194,194,195,195,195,196,196,197,197,198,198,198,199,199,199,199,200,200,201,201,201,202,203,203,203,204,204,204,204,204,205,205,206,206,206,207,207,207,208,208,209,209,209,209,209,209,210,210,210,211,211,211,211,212,212,212,213,213,213,213,214,214,214,215,215,215,215,215,215,215,215,216,216,216,216,217,217,217,217,218,218,218,218,218,219,219,219,219,220,220,220,220,220,221,221,221,221,222,222,222,222,222,222,222,222,222,222,222,222,223,223,223,223,223,223,224,224,224,224,224,225,225,225,225,225,225,226,226,226,226,226,226,227,227,227,227,227,227,227,227,228,228,228,228,228,228,228,229,229,229,229,229,229,229,229,230,230,230,230,230,230,230,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,231,232,232,232,232,232,232,232,232,232,233,233,233,233,233,233,233,233,233,234,234,234,234,234,234,234,234,234,234,235,235,235,235,235,235,235,235,235,236,236,236,236,236,236,236,236,236,236,236,237,237,237,237,237,237,237,237,237,237,237,237,238,238,238,238,238,238,238,238,238,238,238,239,239,239,239,239,239,239,239,239,239,239,239,239,240,240,240,240,240,240,240,240,240,240,240,240,240,241,241,241,241,241,241,241,241,241,241,241,241,241,241,241,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,242,243,243,243,243,243,243,243,243,243,243,243,243,243,243,243,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,244,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,245,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,246,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,247,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,248,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,249,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,250,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,251,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,252,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,253,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,254,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255,255").as_slice()
);
}
}

View File

@@ -28,6 +28,8 @@ pub mod types {
pub type SeedValue = u32;
/// Non-negative integer vector2 with px unit
pub type Resolution = glam::UVec2;
/// DVec2 with px unit
pub type PixelSize = glam::DVec2;
}
// Translation struct between macro and definition

View File

@@ -1,7 +1,7 @@
use super::misc::{ArcType, AsU64, GridType};
use super::{PointId, SegmentId, StrokeId};
use crate::Ctx;
use crate::registry::types::Angle;
use crate::registry::types::{Angle, PixelSize};
use crate::vector::{HandleId, VectorData, VectorDataTable};
use bezier_rs::Subpath;
use glam::DVec2;
@@ -130,7 +130,7 @@ fn star<T: AsU64>(
}
#[node_macro::node(category("Vector: Shape"))]
fn line(_: impl Ctx, _primary: (), #[default((0., -50.))] start: DVec2, #[default((0., 50.))] end: DVec2) -> VectorDataTable {
fn line(_: impl Ctx, _primary: (), #[default((0., -50.))] start: PixelSize, #[default((0., 50.))] end: PixelSize) -> VectorDataTable {
VectorDataTable::new(VectorData::from_subpath(Subpath::new_line(start, end)))
}
@@ -206,7 +206,7 @@ fn grid<T: GridSpacing>(
// Add current point to the grid with offset for odd columns
let current_index = vector_data.point_domain.ids().len();
let a_angles_eaten = ((x + 1) / 2) as f64;
let a_angles_eaten = x.div_ceil(2) as f64;
let b_angles_eaten = (x / 2) as f64;
let offset_y_fraction = b_angles_eaten * tan_b - a_angles_eaten * tan_a;

View File

@@ -5,7 +5,7 @@ use super::style::{Fill, Gradient, GradientStops, Stroke};
use super::{PointId, SegmentDomain, SegmentId, StrokeId, VectorData, VectorDataTable};
use crate::instances::{Instance, InstanceMut, Instances};
use crate::raster::image::ImageFrameTable;
use crate::registry::types::{Angle, Fraction, IntegerCount, Length, Multiplier, Percentage, PixelLength, SeedValue};
use crate::registry::types::{Angle, Fraction, IntegerCount, Length, Multiplier, Percentage, PixelLength, PixelSize, SeedValue};
use crate::renderer::GraphicElementRendered;
use crate::transform::{Footprint, ReferencePoint, Transform, TransformMut};
use crate::vector::PointDomain;
@@ -207,7 +207,7 @@ async fn repeat<I: 'n + Send>(
#[implementations(GraphicGroupTable, VectorDataTable, ImageFrameTable<Color>)] instance: Instances<I>,
#[default(100., 100.)]
// TODO: When using a custom Properties panel layout in document_node_definitions.rs and this default is set, the widget weirdly doesn't show up in the Properties panel. Investigation is needed.
direction: DVec2,
direction: PixelSize,
angle: Angle,
#[default(4)] instances: IntegerCount,
) -> GraphicGroupTable