mirror of
https://github.com/GraphiteEditor/Graphite.git
synced 2026-09-16 06:38:03 +08:00
Rename Raw-rs to Rawkit (#2088)
* Rename within files * Rename in CI * Rename the folder and file names * Rename raw_rs to rawkit * Add example to README * Add initial documentation * Small API changes and extra documentation * Bump versions and stuff * Readme improvements * Merge proc-macro crates into one * Add README to rawkit-proc-macros * Remove keywords and categories * Add licenses to rawkit-proc-macros --------- Co-authored-by: Keavon Chambers <keavon@keavon.com>
This commit is contained in:
13
libraries/rawkit/src/postprocessing/convert_to_rgb.rs
Normal file
13
libraries/rawkit/src/postprocessing/convert_to_rgb.rs
Normal file
@@ -0,0 +1,13 @@
|
||||
use crate::{Pixel, RawImage, CHANNELS_IN_RGB};
|
||||
|
||||
impl RawImage {
|
||||
pub fn convert_to_rgb_fn(&self) -> impl Fn(Pixel) -> [u16; CHANNELS_IN_RGB] {
|
||||
let Some(camera_to_rgb) = self.camera_to_rgb else { todo!() };
|
||||
|
||||
move |pixel: Pixel| {
|
||||
std::array::from_fn(|i| i)
|
||||
.map(|i| camera_to_rgb[i].iter().zip(pixel.values.iter()).map(|(&coeff, &value)| coeff * value as f64).sum())
|
||||
.map(|x: f64| (x as u16).clamp(0, u16::MAX))
|
||||
}
|
||||
}
|
||||
}
|
||||
84
libraries/rawkit/src/postprocessing/gamma_correction.rs
Normal file
84
libraries/rawkit/src/postprocessing/gamma_correction.rs
Normal file
@@ -0,0 +1,84 @@
|
||||
use crate::{Histogram, Image, Pixel, CHANNELS_IN_RGB};
|
||||
use std::f64::consts::E;
|
||||
|
||||
impl Image<u16> {
|
||||
pub fn gamma_correction_fn(&self, histogram: &Histogram) -> impl Fn(Pixel) -> [u16; CHANNELS_IN_RGB] {
|
||||
let percentage = self.width * self.height;
|
||||
|
||||
let mut white = 0;
|
||||
for channel_histogram in histogram {
|
||||
let mut total = 0;
|
||||
for i in (0x20..0x2000).rev() {
|
||||
total += channel_histogram[i] as u64;
|
||||
|
||||
if total * 100 > percentage as u64 {
|
||||
white = white.max(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let curve = generate_gamma_curve(0.45, 4.5, (white << 3) as f64);
|
||||
|
||||
move |pixel: Pixel| pixel.values.map(|value| curve[value as usize])
|
||||
}
|
||||
}
|
||||
|
||||
/// `max_intensity` must be non-zero.
|
||||
fn generate_gamma_curve(power: f64, threshold: f64, max_intensity: f64) -> Vec<u16> {
|
||||
debug_assert!(max_intensity != 0.);
|
||||
|
||||
let (mut bound_start, mut bound_end) = if threshold >= 1. { (0., 1.) } else { (1., 0.) };
|
||||
|
||||
let mut transition_point = 0.;
|
||||
let mut transition_ratio = 0.;
|
||||
let mut curve_adjustment = 0.;
|
||||
|
||||
if threshold != 0. && (threshold - 1.) * (power - 1.) <= 0. {
|
||||
for _ in 0..48 {
|
||||
transition_point = (bound_start + bound_end) / 2.;
|
||||
|
||||
if power != 0. {
|
||||
let temp_transition_ratio = transition_point / threshold;
|
||||
let exponential_power = temp_transition_ratio.powf(-power);
|
||||
let normalized_exponential_power = (exponential_power - 1.) / power;
|
||||
let comparison_result = normalized_exponential_power - (1. / transition_point);
|
||||
|
||||
let bound_to_update = if comparison_result > -1. { &mut bound_end } else { &mut bound_start };
|
||||
*bound_to_update = transition_point;
|
||||
} else {
|
||||
let adjusted_transition_point = E.powf(1. - 1. / transition_point);
|
||||
let transition_point_ratio = transition_point / adjusted_transition_point;
|
||||
|
||||
let bound_to_update = if transition_point_ratio < threshold { &mut bound_end } else { &mut bound_start };
|
||||
*bound_to_update = transition_point;
|
||||
}
|
||||
}
|
||||
|
||||
transition_ratio = transition_point / threshold;
|
||||
|
||||
if power != 0. {
|
||||
curve_adjustment = transition_point * ((1. / power) - 1.);
|
||||
}
|
||||
}
|
||||
|
||||
let mut curve = vec![0xffff; 0x1_0000];
|
||||
let length = curve.len() as f64;
|
||||
|
||||
for (i, entry) in curve.iter_mut().enumerate() {
|
||||
let ratio = (i as f64) / max_intensity;
|
||||
if ratio < 1. {
|
||||
let altered_ratio = if ratio < transition_ratio {
|
||||
ratio * threshold
|
||||
} else if power != 0. {
|
||||
ratio.powf(power) * (1. + curve_adjustment) - curve_adjustment
|
||||
} else {
|
||||
ratio.ln() * transition_point + 1.
|
||||
};
|
||||
|
||||
*entry = (length * altered_ratio) as u16;
|
||||
}
|
||||
}
|
||||
|
||||
curve
|
||||
}
|
||||
4
libraries/rawkit/src/postprocessing/mod.rs
Normal file
4
libraries/rawkit/src/postprocessing/mod.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub mod convert_to_rgb;
|
||||
pub mod gamma_correction;
|
||||
pub mod record_histogram;
|
||||
pub mod transform;
|
||||
29
libraries/rawkit/src/postprocessing/record_histogram.rs
Normal file
29
libraries/rawkit/src/postprocessing/record_histogram.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use crate::{Histogram, Pixel, PixelTransform, RawImage, CHANNELS_IN_RGB};
|
||||
|
||||
impl RawImage {
|
||||
pub fn record_histogram_fn(&self) -> RecordHistogram {
|
||||
RecordHistogram::new()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct RecordHistogram {
|
||||
pub histogram: Histogram,
|
||||
}
|
||||
|
||||
impl RecordHistogram {
|
||||
fn new() -> RecordHistogram {
|
||||
RecordHistogram {
|
||||
histogram: [[0; 0x2000]; CHANNELS_IN_RGB],
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl PixelTransform for &mut RecordHistogram {
|
||||
fn apply(&mut self, pixel: Pixel) -> [u16; CHANNELS_IN_RGB] {
|
||||
self.histogram
|
||||
.iter_mut()
|
||||
.zip(pixel.values.iter())
|
||||
.for_each(|(histogram, &value)| histogram[value as usize >> CHANNELS_IN_RGB] += 1);
|
||||
pixel.values
|
||||
}
|
||||
}
|
||||
70
libraries/rawkit/src/postprocessing/transform.rs
Normal file
70
libraries/rawkit/src/postprocessing/transform.rs
Normal file
@@ -0,0 +1,70 @@
|
||||
use crate::{Image, Pixel, Transform};
|
||||
|
||||
impl Image<u16> {
|
||||
pub fn transform_iter(&self) -> (usize, usize, impl Iterator<Item = Pixel> + use<'_>) {
|
||||
let (final_width, final_height) = if self.transform.will_swap_coordinates() {
|
||||
(self.height, self.width)
|
||||
} else {
|
||||
(self.width, self.height)
|
||||
};
|
||||
|
||||
let index_0_0 = inverse_transform_index(self.transform, 0, 0, self.width, self.height);
|
||||
let index_0_1 = inverse_transform_index(self.transform, 0, 1, self.width, self.height);
|
||||
let index_1_0 = inverse_transform_index(self.transform, 1, 0, self.width, self.height);
|
||||
|
||||
let column_step = (index_0_1.0 - index_0_0.0, index_0_1.1 - index_0_0.1);
|
||||
let row_step = (index_1_0.0 - index_0_0.0, index_1_0.1 - index_0_0.1);
|
||||
let mut index = index_0_0;
|
||||
|
||||
let channels = self.channels as usize;
|
||||
|
||||
(
|
||||
final_width,
|
||||
final_height,
|
||||
(0..final_height).flat_map(move |row| {
|
||||
let temp = (0..final_width).map(move |column| {
|
||||
let initial_index = (self.width as i64 * index.0 + index.1) as usize;
|
||||
let pixel = &self.data[channels * initial_index..channels * (initial_index + 1)];
|
||||
index = (index.0 + column_step.0, index.1 + column_step.1);
|
||||
|
||||
Pixel {
|
||||
values: pixel.try_into().unwrap(),
|
||||
row,
|
||||
column,
|
||||
}
|
||||
});
|
||||
|
||||
index = (index.0 + row_step.0, index.1 + row_step.1);
|
||||
|
||||
temp
|
||||
}),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub fn inverse_transform_index(transform: Transform, mut row: usize, mut column: usize, width: usize, height: usize) -> (i64, i64) {
|
||||
let value = match transform {
|
||||
Transform::Horizontal => 0,
|
||||
Transform::MirrorHorizontal => 1,
|
||||
Transform::Rotate180 => 3,
|
||||
Transform::MirrorVertical => 2,
|
||||
Transform::MirrorHorizontalRotate270 => 4,
|
||||
Transform::Rotate90 => 6,
|
||||
Transform::MirrorHorizontalRotate90 => 7,
|
||||
Transform::Rotate270 => 5,
|
||||
};
|
||||
|
||||
if value & 4 != 0 {
|
||||
std::mem::swap(&mut row, &mut column)
|
||||
}
|
||||
|
||||
if value & 2 != 0 {
|
||||
row = height - 1 - row;
|
||||
}
|
||||
|
||||
if value & 1 != 0 {
|
||||
column = width - 1 - column;
|
||||
}
|
||||
|
||||
(row as i64, column as i64)
|
||||
}
|
||||
Reference in New Issue
Block a user