Clippy 1.99: chunks_exact with a constant size -> as_chunks; drop a no-op Option filter
Rust 1.99's clippy adds chunks_exact_to_as_chunks and some_filter, which broke the Clippy step on every CI runner (it uses the latest stable). All sites are mechanical: as_chunks drops the remainder exactly like chunks_exact. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
574d4fe7da
commit
1c09936154
|
|
@ -65,7 +65,9 @@ pub(crate) fn oil_paint(src: &Image, out: Rect, ctx: &Ctx, spec: &OilSpec) -> Ve
|
||||||
gauss_blur_n(&mut efg, ww, wh, 3, tensor_sigma(spec.scale));
|
gauss_blur_n(&mut efg, ww, wh, 3, tensor_sigma(spec.scale));
|
||||||
// 4. Stroke direction = minor eigenvector (along edges).
|
// 4. Stroke direction = minor eigenvector (along edges).
|
||||||
let tangent: Vec<(f32, f32)> = efg
|
let tangent: Vec<(f32, f32)> = efg
|
||||||
.chunks_exact(3)
|
.as_chunks::<3>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
.map(|t| {
|
.map(|t| {
|
||||||
let (e, f, g) = (t[0], t[1], t[2]);
|
let (e, f, g) = (t[0], t[1], t[2]);
|
||||||
let l1 = 0.5 * (e + g + ((e - g) * (e - g) + 4.0 * f * f).sqrt());
|
let l1 = 0.5 * (e + g + ((e - g) * (e - g) + 4.0 * f * f).sqrt());
|
||||||
|
|
|
||||||
|
|
@ -298,7 +298,7 @@ mod tests {
|
||||||
let (w, h, ch) = (8, 1, 4);
|
let (w, h, ch) = (8, 1, 4);
|
||||||
let data: Vec<f32> = (0..w).flat_map(|x| if x < 4 { [1.0, 0.0, 0.0, 1.0] } else { [0.0, 1.0, 0.0, 0.0] }).collect();
|
let data: Vec<f32> = (0..w).flat_map(|x| if x < 4 { [1.0, 0.0, 0.0, 1.0] } else { [0.0, 1.0, 0.0, 0.0] }).collect();
|
||||||
let b = local_blur(&data, w, h, ch, Some(3), (2, 0, 6, 1), 1.0);
|
let b = local_blur(&data, w, h, ch, Some(3), (2, 0, 6, 1), 1.0);
|
||||||
for p in b.chunks_exact(4) {
|
for p in b.as_chunks::<4>().0 {
|
||||||
if p[3] > 0.01 {
|
if p[3] > 0.01 {
|
||||||
assert!(p[0] > 0.99 && p[1] < 0.01, "{p:?}");
|
assert!(p[0] > 0.99 && p[1] < 0.01, "{p:?}");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -547,7 +547,7 @@ pub fn polygon(points: &[(f32, f32)], area: Rect, anti_alias: bool) -> Vec<f32>
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xs.sort_by(|a, b| a.total_cmp(b));
|
xs.sort_by(|a, b| a.total_cmp(b));
|
||||||
for span in xs.chunks_exact(2) {
|
for span in xs.as_chunks::<2>().0 {
|
||||||
let (x0, x1) = ((span[0] - area.x0 as f32).max(0.0), (span[1] - area.x0 as f32).min(w as f32));
|
let (x0, x1) = ((span[0] - area.x0 as f32).max(0.0), (span[1] - area.x0 as f32).min(w as f32));
|
||||||
if x1 <= x0 {
|
if x1 <= x0 {
|
||||||
continue;
|
continue;
|
||||||
|
|
|
||||||
|
|
@ -127,7 +127,7 @@ fn blur_preserves_flat_colour_and_mass() {
|
||||||
for p in [FilterParams::GaussianBlur { radius: 2.0 }, FilterParams::BoxBlur { radius: 3.0 }] {
|
for p in [FilterParams::GaussianBlur { radius: 2.0 }, FilterParams::BoxBlur { radius: 3.0 }] {
|
||||||
let out = run(&small, &p);
|
let out = run(&small, &p);
|
||||||
let big = Rect::new(-10, -10, 40, 40);
|
let big = Rect::new(-10, -10, 40, 40);
|
||||||
let sum: f32 = out.read_region(big).chunks_exact(4).map(|px| px[3]).sum();
|
let sum: f32 = out.read_region(big).as_chunks::<4>().0.iter().map(|px| px[3]).sum();
|
||||||
assert!((sum - 100.0).abs() < 0.01, "{}: {sum}", p.label());
|
assert!((sum - 100.0).abs() < 0.01, "{}: {sum}", p.label());
|
||||||
// No colour bleeding from transparent pixels.
|
// No colour bleeding from transparent pixels.
|
||||||
let edge = out.pixel(9, 15);
|
let edge = out.pixel(9, 15);
|
||||||
|
|
@ -176,7 +176,7 @@ fn unsharp_threshold_and_contrast() {
|
||||||
let sharp = run(&s, &FilterParams::UnsharpMask { amount: 200.0, radius: 2.0, threshold: 0.0 });
|
let sharp = run(&s, &FilterParams::UnsharpMask { amount: 200.0, radius: 2.0, threshold: 0.0 });
|
||||||
let var = |surf: &Surface| {
|
let var = |surf: &Surface| {
|
||||||
let v = surf.read_region(Rect::new(5, 5, 35, 25));
|
let v = surf.read_region(Rect::new(5, 5, 35, 25));
|
||||||
let reds: Vec<f32> = v.chunks_exact(4).map(|p| p[0]).collect();
|
let reds: Vec<f32> = v.as_chunks::<4>().0.iter().map(|p| p[0]).collect();
|
||||||
let m = reds.iter().sum::<f32>() / reds.len() as f32;
|
let m = reds.iter().sum::<f32>() / reds.len() as f32;
|
||||||
reds.iter().map(|r| (r - m).powi(2)).sum::<f32>()
|
reds.iter().map(|r| (r - m).powi(2)).sum::<f32>()
|
||||||
};
|
};
|
||||||
|
|
@ -198,7 +198,7 @@ fn noise_is_deterministic_monochrome_and_centred() {
|
||||||
assert_eq!(a, run(&s, &p));
|
assert_eq!(a, run(&s, &p));
|
||||||
let v = a.read_region(R);
|
let v = a.read_region(R);
|
||||||
let mut mean = 0.0;
|
let mut mean = 0.0;
|
||||||
for px in v.chunks_exact(4) {
|
for px in v.as_chunks::<4>().0 {
|
||||||
assert_eq!(px[0], px[1]);
|
assert_eq!(px[0], px[1]);
|
||||||
assert_eq!(px[1], px[2]);
|
assert_eq!(px[1], px[2]);
|
||||||
assert!((px[0] - 0.5).abs() <= 0.25 + 1e-6);
|
assert!((px[0] - 0.5).abs() <= 0.25 + 1e-6);
|
||||||
|
|
|
||||||
|
|
@ -303,7 +303,7 @@ fn mezzotint_is_binary_and_tracks_brightness() {
|
||||||
let out = run(&s, &FilterParams::Mezzotint { kind: MezzotintType::FineDots, seed: 1 });
|
let out = run(&s, &FilterParams::Mezzotint { kind: MezzotintType::FineDots, seed: 1 });
|
||||||
let v = out.read_region(R);
|
let v = out.read_region(R);
|
||||||
let mut mean = [0.0f32; 3];
|
let mut mean = [0.0f32; 3];
|
||||||
for px in v.chunks_exact(4) {
|
for px in v.as_chunks::<4>().0 {
|
||||||
for k in 0..3 {
|
for k in 0..3 {
|
||||||
assert!(px[k] == 0.0 || px[k] == 1.0);
|
assert!(px[k] == 0.0 || px[k] == 1.0);
|
||||||
mean[k] += px[k] / 1200.0;
|
mean[k] += px[k] / 1200.0;
|
||||||
|
|
@ -318,10 +318,10 @@ fn halftone_covers_by_ink() {
|
||||||
let w = run(&flat(SampleType::F32, R, WHITE), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
let w = run(&flat(SampleType::F32, R, WHITE), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
||||||
assert!(w.read_region(R).iter().all(|&v| (v - 1.0).abs() < 1e-6), "white paper stays white");
|
assert!(w.read_region(R).iter().all(|&v| (v - 1.0).abs() < 1e-6), "white paper stays white");
|
||||||
let b = run(&flat(SampleType::F32, R, BLACK), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
let b = run(&flat(SampleType::F32, R, BLACK), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
||||||
let mean_b: f32 = b.read_region(R).chunks_exact(4).map(|p| p[0]).sum::<f32>() / 1200.0;
|
let mean_b: f32 = b.read_region(R).as_chunks::<4>().0.iter().map(|p| p[0]).sum::<f32>() / 1200.0;
|
||||||
assert!(mean_b < 0.05, "black is fully inked: {mean_b}");
|
assert!(mean_b < 0.05, "black is fully inked: {mean_b}");
|
||||||
let g = run(&flat(SampleType::F32, R, [0.5, 0.5, 0.5, 1.0]), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
let g = run(&flat(SampleType::F32, R, [0.5, 0.5, 0.5, 1.0]), &FilterParams::ColorHalftone { max_radius: 4.0, angles });
|
||||||
let mean_g: f32 = g.read_region(R).chunks_exact(4).map(|p| p[1]).sum::<f32>() / 1200.0;
|
let mean_g: f32 = g.read_region(R).as_chunks::<4>().0.iter().map(|p| p[1]).sum::<f32>() / 1200.0;
|
||||||
assert!((mean_g - 0.5).abs() < 0.12, "mid gray ≈ half coverage: {mean_g}");
|
assert!((mean_g - 0.5).abs() < 0.12, "mid gray ≈ half coverage: {mean_g}");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -330,8 +330,8 @@ fn pointillize_shows_canvas() {
|
||||||
let s = flat(SampleType::F32, R, [0.0, 0.0, 1.0, 1.0]);
|
let s = flat(SampleType::F32, R, [0.0, 0.0, 1.0, 1.0]);
|
||||||
let out = run(&s, &FilterParams::Pointillize { cell_size: 10.0, seed: 3, background: [1.0, 0.0, 0.0, 1.0] });
|
let out = run(&s, &FilterParams::Pointillize { cell_size: 10.0, seed: 3, background: [1.0, 0.0, 0.0, 1.0] });
|
||||||
let v = out.read_region(R);
|
let v = out.read_region(R);
|
||||||
assert!(v.chunks_exact(4).any(|p| p[0] > 0.99 && p[2] < 0.01), "canvas visible between dots");
|
assert!(v.as_chunks::<4>().0.iter().any(|p| p[0] > 0.99 && p[2] < 0.01), "canvas visible between dots");
|
||||||
assert!(v.chunks_exact(4).any(|p| p[2] > 0.9), "dots take the image colour");
|
assert!(v.as_chunks::<4>().0.iter().any(|p| p[2] > 0.9), "dots take the image colour");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -372,8 +372,8 @@ fn tiles_leave_gaps_with_fill() {
|
||||||
let out =
|
let out =
|
||||||
run(&s, &FilterParams::Tiles { count: 3, max_offset: 40.0, fill: TileFill::Foreground, foreground: [0.0, 1.0, 0.0, 1.0], background: WHITE, seed: 2 });
|
run(&s, &FilterParams::Tiles { count: 3, max_offset: 40.0, fill: TileFill::Foreground, foreground: [0.0, 1.0, 0.0, 1.0], background: WHITE, seed: 2 });
|
||||||
let v = out.read_region(R);
|
let v = out.read_region(R);
|
||||||
assert!(v.chunks_exact(4).any(|p| p[1] > 0.99), "foreground gaps");
|
assert!(v.as_chunks::<4>().0.iter().any(|p| p[1] > 0.99), "foreground gaps");
|
||||||
assert!(v.chunks_exact(4).filter(|p| p[2] > 0.99).count() > 600, "mostly tiles");
|
assert!(v.as_chunks::<4>().0.iter().filter(|p| p[2] > 0.99).count() > 600, "mostly tiles");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -409,7 +409,7 @@ fn fibers_lie_between_colours_and_are_seeded() {
|
||||||
let p = FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 1, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] };
|
let p = FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 1, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] };
|
||||||
let a = run(&s, &p);
|
let a = run(&s, &p);
|
||||||
assert_eq!(a, run(&s, &p));
|
assert_eq!(a, run(&s, &p));
|
||||||
for px in a.read_region(R).chunks_exact(4) {
|
for px in a.read_region(R).as_chunks::<4>().0 {
|
||||||
assert!((px[0] + px[2] - 1.0).abs() < 1e-5 && px[1].abs() < 1e-6);
|
assert!((px[0] + px[2] - 1.0).abs() < 1e-5 && px[1].abs() < 1e-6);
|
||||||
}
|
}
|
||||||
let b = run(&s, &FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 2, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] });
|
let b = run(&s, &FilterParams::Fibers { variance: 16.0, strength: 4.0, seed: 2, foreground: [1.0, 0.0, 0.0, 1.0], background: [0.0, 0.0, 1.0, 1.0] });
|
||||||
|
|
@ -462,7 +462,7 @@ fn lighting_point_light_falls_off() {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn variance(s: &Surface, r: Rect, c: usize) -> f32 {
|
fn variance(s: &Surface, r: Rect, c: usize) -> f32 {
|
||||||
let v: Vec<f32> = s.read_region(r).chunks_exact(4).map(|p| p[c]).collect();
|
let v: Vec<f32> = s.read_region(r).as_chunks::<4>().0.iter().map(|p| p[c]).collect();
|
||||||
let m = v.iter().sum::<f32>() / v.len() as f32;
|
let m = v.iter().sum::<f32>() / v.len() as f32;
|
||||||
v.iter().map(|x| (x - m).powi(2)).sum::<f32>() / v.len() as f32
|
v.iter().map(|x| (x - m).powi(2)).sum::<f32>() / v.len() as f32
|
||||||
}
|
}
|
||||||
|
|
@ -525,7 +525,7 @@ fn shaped_blurs_spread_a_point_into_the_shape() {
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
// A triangle iris pointing up: the bokeh reaches farther below the point than above it... and specular boost brightens.
|
// A triangle iris pointing up: the bokeh reaches farther below the point than above it... and specular boost brightens.
|
||||||
let sum: f32 = lb.read_region(R).chunks_exact(4).map(|p| p[0]).sum();
|
let sum: f32 = lb.read_region(R).as_chunks::<4>().0.iter().map(|p| p[0]).sum();
|
||||||
assert!(sum > 1.5, "highlight bloomed: {sum}");
|
assert!(sum > 1.5, "highlight bloomed: {sum}");
|
||||||
assert!(lb.pixel(20, 15 + 5)[0] != lb.pixel(20, 15 - 5)[0], "triangular, not circular");
|
assert!(lb.pixel(20, 15 + 5)[0] != lb.pixel(20, 15 - 5)[0], "triangular, not circular");
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -283,7 +283,7 @@ pub fn warp_mesh_gray(s: &Surface, f: &(dyn Fn(f64, f64) -> (f64, f64) + Sync),
|
||||||
let b = w.content_bounds();
|
let b = w.content_bounds();
|
||||||
if !b.is_empty() {
|
if !b.is_empty() {
|
||||||
let px = w.read_region(b);
|
let px = w.read_region(b);
|
||||||
let flat: Vec<f32> = px.chunks_exact(2).map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect();
|
let flat: Vec<f32> = px.as_chunks::<2>().0.iter().map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect();
|
||||||
out.write_region(b, &flat);
|
out.write_region(b, &flat);
|
||||||
}
|
}
|
||||||
out.prune();
|
out.prune();
|
||||||
|
|
|
||||||
|
|
@ -186,10 +186,10 @@ pub fn parse_look(text: &str) -> Result<LutFile, LutError> {
|
||||||
let size: usize = tag("size").and_then(|s| s.parse().ok()).ok_or_else(|| LutError("no <size> in .look".into()))?;
|
let size: usize = tag("size").and_then(|s| s.parse().ok()).ok_or_else(|| LutError("no <size> in .look".into()))?;
|
||||||
let hex: Vec<u8> = tag("data").ok_or_else(|| LutError("no <data> in .look".into()))?.bytes().filter(u8::is_ascii_hexdigit).collect();
|
let hex: Vec<u8> = tag("data").ok_or_else(|| LutError("no <data> in .look".into()))?.bytes().filter(u8::is_ascii_hexdigit).collect();
|
||||||
let nib = |c: u8| (c as char).to_digit(16).unwrap_or(0) as u8;
|
let nib = |c: u8| (c as char).to_digit(16).unwrap_or(0) as u8;
|
||||||
let bytes: Vec<u8> = hex.chunks_exact(2).map(|p| nib(p[0]) << 4 | nib(p[1])).collect();
|
let bytes: Vec<u8> = hex.as_chunks::<2>().0.iter().map(|p| nib(p[0]) << 4 | nib(p[1])).collect();
|
||||||
let floats: Vec<f32> = bytes.chunks_exact(4).map(|b| f32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect();
|
let floats: Vec<f32> = bytes.as_chunks::<4>().0.iter().map(|b| f32::from_le_bytes([b[0], b[1], b[2], b[3]])).collect();
|
||||||
let n3 = size.pow(3);
|
let n3 = size.pow(3);
|
||||||
let data = if floats.len() == n3 * 4 { floats.chunks_exact(4).flat_map(|c| [c[0], c[1], c[2]]).collect() } else { floats };
|
let data = if floats.len() == n3 * 4 { floats.as_chunks::<4>().0.iter().flat_map(|c| [c[0], c[1], c[2]]).collect() } else { floats };
|
||||||
LutFile { title: tag("title").unwrap_or_default(), size, data }.check()
|
LutFile { title: tag("title").unwrap_or_default(), size, data }.check()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -200,7 +200,7 @@ pub fn write_cube(l: &LutFile) -> String {
|
||||||
s.push_str(&format!("TITLE \"{}\"\n", l.title.replace('"', "'")));
|
s.push_str(&format!("TITLE \"{}\"\n", l.title.replace('"', "'")));
|
||||||
}
|
}
|
||||||
s.push_str(&format!("LUT_3D_SIZE {}\n", l.size));
|
s.push_str(&format!("LUT_3D_SIZE {}\n", l.size));
|
||||||
for c in l.data.chunks_exact(3) {
|
for c in l.data.as_chunks::<3>().0 {
|
||||||
s.push_str(&format!("{:.6} {:.6} {:.6}\n", c[0], c[1], c[2]));
|
s.push_str(&format!("{:.6} {:.6} {:.6}\n", c[0], c[1], c[2]));
|
||||||
}
|
}
|
||||||
s
|
s
|
||||||
|
|
|
||||||
|
|
@ -525,7 +525,7 @@ fn parse_curve(d: &[u8]) -> Result<(Curve, usize), CmsError> {
|
||||||
return Err(CmsError::Invalid("curve too long".into()));
|
return Err(CmsError::Invalid("curve too long".into()));
|
||||||
}
|
}
|
||||||
let s = r.slice(12, n * 2)?;
|
let s = r.slice(12, n * 2)?;
|
||||||
let t = s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect();
|
let t = s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect();
|
||||||
Ok((Curve::Table(t), len))
|
Ok((Curve::Table(t), len))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -586,7 +586,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result<Lut, CmsError> {
|
||||||
for _ in 0..count {
|
for _ in 0..count {
|
||||||
let s = r.slice(*off, len * bps)?;
|
let s = r.slice(*off, len * bps)?;
|
||||||
let t: Vec<f32> = if wide {
|
let t: Vec<f32> = if wide {
|
||||||
s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect()
|
s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect()
|
||||||
} else {
|
} else {
|
||||||
s.iter().map(|b| *b as f32 / 255.0).collect()
|
s.iter().map(|b| *b as f32 / 255.0).collect()
|
||||||
};
|
};
|
||||||
|
|
@ -603,7 +603,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result<Lut, CmsError> {
|
||||||
let total = nodes as usize * o;
|
let total = nodes as usize * o;
|
||||||
let s = r.slice(off, total * bps)?;
|
let s = r.slice(off, total * bps)?;
|
||||||
let data: Vec<f32> = if wide {
|
let data: Vec<f32> = if wide {
|
||||||
s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect()
|
s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect()
|
||||||
} else {
|
} else {
|
||||||
s.iter().map(|b| *b as f32 / 255.0).collect()
|
s.iter().map(|b| *b as f32 / 255.0).collect()
|
||||||
};
|
};
|
||||||
|
|
@ -653,7 +653,7 @@ fn parse_lut(d: &[u8], a2b: bool) -> Result<Lut, CmsError> {
|
||||||
let total = nodes as usize * cout;
|
let total = nodes as usize * cout;
|
||||||
let data: Vec<f32> = match prec {
|
let data: Vec<f32> = match prec {
|
||||||
1 => r.slice(off + 20, total)?.iter().map(|b| *b as f32 / 255.0).collect(),
|
1 => r.slice(off + 20, total)?.iter().map(|b| *b as f32 / 255.0).collect(),
|
||||||
2 => r.slice(off + 20, total * 2)?.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(),
|
2 => r.slice(off + 20, total * 2)?.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as f32 / 65535.0).collect(),
|
||||||
_ => return Err(CmsError::Invalid(format!("CLUT precision {prec}"))),
|
_ => return Err(CmsError::Invalid(format!("CLUT precision {prec}"))),
|
||||||
};
|
};
|
||||||
Ok(Stage::Clut(Clut::new(grid, cout, data)))
|
Ok(Stage::Clut(Clut::new(grid, cout, data)))
|
||||||
|
|
@ -730,7 +730,7 @@ fn parse_text(d: &[u8]) -> String {
|
||||||
}
|
}
|
||||||
let Some((off, len)) = best else { return String::new() };
|
let Some((off, len)) = best else { return String::new() };
|
||||||
let Ok(s) = r.slice(off, len) else { return String::new() };
|
let Ok(s) = r.slice(off, len) else { return String::new() };
|
||||||
let units: Vec<u16> = s.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let units: Vec<u16> = s.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
String::from_utf16_lossy(&units).trim_end_matches('\0').trim().to_string()
|
String::from_utf16_lossy(&units).trim_end_matches('\0').trim().to_string()
|
||||||
}
|
}
|
||||||
_ => String::new(),
|
_ => String::new(),
|
||||||
|
|
|
||||||
|
|
@ -429,18 +429,18 @@ impl Transform {
|
||||||
let run = |(s, d): (&[u8], &mut [u8])| match sample {
|
let run = |(s, d): (&[u8], &mut [u8])| match sample {
|
||||||
SampleKind::U8 => self.run_u8(s, src_stride, d, dst_stride, extra),
|
SampleKind::U8 => self.run_u8(s, src_stride, d, dst_stride, extra),
|
||||||
SampleKind::U16 => {
|
SampleKind::U16 => {
|
||||||
let a: Vec<u16> = s.chunks_exact(2).map(|b| u16::from_ne_bytes([b[0], b[1]])).collect();
|
let a: Vec<u16> = s.as_chunks::<2>().0.iter().map(|b| u16::from_ne_bytes([b[0], b[1]])).collect();
|
||||||
let mut o: Vec<u16> = d.chunks_exact(2).map(|b| u16::from_ne_bytes([b[0], b[1]])).collect();
|
let mut o: Vec<u16> = d.as_chunks::<2>().0.iter().map(|b| u16::from_ne_bytes([b[0], b[1]])).collect();
|
||||||
self.run_u16(&a, src_stride, &mut o, dst_stride, extra);
|
self.run_u16(&a, src_stride, &mut o, dst_stride, extra);
|
||||||
for (b, v) in d.chunks_exact_mut(2).zip(o) {
|
for (b, v) in d.as_chunks_mut::<2>().0.iter_mut().zip(o) {
|
||||||
b.copy_from_slice(&v.to_ne_bytes());
|
b.copy_from_slice(&v.to_ne_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
SampleKind::F32 => {
|
SampleKind::F32 => {
|
||||||
let a: Vec<f32> = s.chunks_exact(4).map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect();
|
let a: Vec<f32> = s.as_chunks::<4>().0.iter().map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect();
|
||||||
let mut o: Vec<f32> = d.chunks_exact(4).map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect();
|
let mut o: Vec<f32> = d.as_chunks::<4>().0.iter().map(|b| f32::from_ne_bytes([b[0], b[1], b[2], b[3]])).collect();
|
||||||
self.run_f32(&a, src_stride, &mut o, dst_stride, extra);
|
self.run_f32(&a, src_stride, &mut o, dst_stride, extra);
|
||||||
for (b, v) in d.chunks_exact_mut(4).zip(o) {
|
for (b, v) in d.as_chunks_mut::<4>().0.iter_mut().zip(o) {
|
||||||
b.copy_from_slice(&v.to_ne_bytes());
|
b.copy_from_slice(&v.to_ne_bytes());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -133,7 +133,7 @@ pub(crate) fn decode(bytes: &[u8], limits: &Limits) -> Result<Image, CodecError>
|
||||||
// Adobe-style CMYK is stored inverted (255 = no ink).
|
// Adobe-style CMYK is stored inverted (255 = no ink).
|
||||||
ColorSpace::CMYK => px.iter_mut().for_each(|v| *v = 255 - *v),
|
ColorSpace::CMYK => px.iter_mut().for_each(|v| *v = 255 - *v),
|
||||||
ColorSpace::YCCK => {
|
ColorSpace::YCCK => {
|
||||||
for p in px.chunks_exact_mut(4) {
|
for p in px.as_chunks_mut::<4>().0 {
|
||||||
let (y, cb, cr) = (p[0] as f32, p[1] as f32 - 128.0, p[2] as f32 - 128.0);
|
let (y, cb, cr) = (p[0] as f32, p[1] as f32 - 128.0, p[2] as f32 - 128.0);
|
||||||
let c = y + 1.402 * cr;
|
let c = y + 1.402 * cr;
|
||||||
let m = y - 0.344_136 * cb - 0.714_136 * cr;
|
let m = y - 0.344_136 * cb - 0.714_136 * cr;
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ pub(crate) fn decode(bytes: &[u8], limits: &Limits) -> Result<Image, CodecError>
|
||||||
// tolerated: pixel data is already complete.
|
// tolerated: pixel data is already complete.
|
||||||
let _ = reader.finish();
|
let _ = reader.finish();
|
||||||
if sample == SampleType::U16 {
|
if sample == SampleType::U16 {
|
||||||
for c in buf.chunks_exact_mut(2) {
|
for c in buf.as_chunks_mut::<2>().0 {
|
||||||
let v = u16::from_be_bytes([c[0], c[1]]);
|
let v = u16::from_be_bytes([c[0], c[1]]);
|
||||||
c.copy_from_slice(&v.to_ne_bytes());
|
c.copy_from_slice(&v.to_ne_bytes());
|
||||||
}
|
}
|
||||||
|
|
@ -114,7 +114,7 @@ pub(crate) fn encode(src: &Image, plan: Plan, opts: &EncodeOptions) -> Result<Ve
|
||||||
// Big-endian sample bytes.
|
// Big-endian sample bytes.
|
||||||
let mut data = img.data().to_vec();
|
let mut data = img.data().to_vec();
|
||||||
if depth == png::BitDepth::Sixteen {
|
if depth == png::BitDepth::Sixteen {
|
||||||
for c in data.chunks_exact_mut(2) {
|
for c in data.as_chunks_mut::<2>().0 {
|
||||||
let v = u16::from_ne_bytes([c[0], c[1]]);
|
let v = u16::from_ne_bytes([c[0], c[1]]);
|
||||||
c.copy_from_slice(&v.to_be_bytes());
|
c.copy_from_slice(&v.to_be_bytes());
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ fn read_binary(data: &[u8], n: usize, maxval: u32) -> Result<Vec<u32>, CodecErro
|
||||||
if data.len() < n * 2 {
|
if data.len() < n * 2 {
|
||||||
return Err(err("truncated raster"));
|
return Err(err("truncated raster"));
|
||||||
}
|
}
|
||||||
Ok(data[..n * 2].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]]) as u32).collect())
|
Ok(data[..n * 2].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]]) as u32).collect())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -243,7 +243,7 @@ fn is_avif_ftyp(b: &[u8]) -> bool {
|
||||||
let size = u32::from_be_bytes([b[0], b[1], b[2], b[3]]) as usize;
|
let size = u32::from_be_bytes([b[0], b[1], b[2], b[3]]) as usize;
|
||||||
let end = size.clamp(12, b.len().min(64));
|
let end = size.clamp(12, b.len().min(64));
|
||||||
let brands = &b[8..end];
|
let brands = &b[8..end];
|
||||||
brands.chunks_exact(4).enumerate().any(|(i, c)| i != 1 && (c == b"avif" || c == b"avis"))
|
brands.as_chunks::<4>().0.iter().enumerate().any(|(i, c)| i != 1 && (c == b"avif" || c == b"avis"))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn looks_like_tga(b: &[u8]) -> bool {
|
fn looks_like_tga(b: &[u8]) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -238,17 +238,17 @@ impl Image {
|
||||||
|
|
||||||
/// Copy samples out as `u16` (only when the sample type is `U16`).
|
/// Copy samples out as `u16` (only when the sample type is `U16`).
|
||||||
pub fn to_u16_samples(&self) -> Option<Vec<u16>> {
|
pub fn to_u16_samples(&self) -> Option<Vec<u16>> {
|
||||||
(self.sample == SampleType::U16).then(|| self.data.chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]])).collect())
|
(self.sample == SampleType::U16).then(|| self.data.as_chunks::<2>().0.iter().map(|c| u16::from_ne_bytes([c[0], c[1]])).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy samples out as `f16` (only when the sample type is `F16`).
|
/// Copy samples out as `f16` (only when the sample type is `F16`).
|
||||||
pub fn to_f16_samples(&self) -> Option<Vec<f16>> {
|
pub fn to_f16_samples(&self) -> Option<Vec<f16>> {
|
||||||
(self.sample == SampleType::F16).then(|| self.data.chunks_exact(2).map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]]))).collect())
|
(self.sample == SampleType::F16).then(|| self.data.as_chunks::<2>().0.iter().map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]]))).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Copy samples out as `f32` (only when the sample type is `F32`).
|
/// Copy samples out as `f32` (only when the sample type is `F32`).
|
||||||
pub fn to_f32_samples(&self) -> Option<Vec<f32>> {
|
pub fn to_f32_samples(&self) -> Option<Vec<f32>> {
|
||||||
(self.sample == SampleType::F32).then(|| self.data.chunks_exact(4).map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect())
|
(self.sample == SampleType::F32).then(|| self.data.as_chunks::<4>().0.iter().map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Sample `index` (in samples, not bytes) as a normalized f32.
|
/// Sample `index` (in samples, not bytes) as a normalized f32.
|
||||||
|
|
@ -363,9 +363,9 @@ pub(crate) fn read_normalized(data: &[u8], sample: SampleType, i: usize) -> f32
|
||||||
pub(crate) fn to_normalized(data: &[u8], sample: SampleType) -> Vec<f32> {
|
pub(crate) fn to_normalized(data: &[u8], sample: SampleType) -> Vec<f32> {
|
||||||
match sample {
|
match sample {
|
||||||
SampleType::U8 => data.iter().map(|&v| v as f32 / 255.0).collect(),
|
SampleType::U8 => data.iter().map(|&v| v as f32 / 255.0).collect(),
|
||||||
SampleType::U16 => data.chunks_exact(2).map(|c| u16::from_ne_bytes([c[0], c[1]]) as f32 / 65535.0).collect(),
|
SampleType::U16 => data.as_chunks::<2>().0.iter().map(|c| u16::from_ne_bytes([c[0], c[1]]) as f32 / 65535.0).collect(),
|
||||||
SampleType::F16 => data.chunks_exact(2).map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]])).to_f32()).collect(),
|
SampleType::F16 => data.as_chunks::<2>().0.iter().map(|c| f16::from_bits(u16::from_ne_bytes([c[0], c[1]])).to_f32()).collect(),
|
||||||
SampleType::F32 => data.chunks_exact(4).map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect(),
|
SampleType::F32 => data.as_chunks::<4>().0.iter().map(|c| f32::from_ne_bytes([c[0], c[1], c[2], c[3]])).collect(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -48,7 +48,7 @@ impl Buffer {
|
||||||
}
|
}
|
||||||
pub fn to_rgba8(&self) -> Rgba8Image {
|
pub fn to_rgba8(&self) -> Rgba8Image {
|
||||||
let mut img = Rgba8Image::new(self.rect.width(), self.rect.height());
|
let mut img = Rgba8Image::new(self.rect.width(), self.rect.height());
|
||||||
for (o, p) in img.pixels.chunks_exact_mut(4).zip(&self.px) {
|
for (o, p) in img.pixels.as_chunks_mut::<4>().0.iter_mut().zip(&self.px) {
|
||||||
for (dst, v) in o.iter_mut().zip(p) {
|
for (dst, v) in o.iter_mut().zip(p) {
|
||||||
*dst = (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8;
|
*dst = (v.clamp(0.0, 1.0) * 255.0 + 0.5) as u8;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -329,7 +329,7 @@ impl ColorState {
|
||||||
let check =
|
let check =
|
||||||
if pv.gamut_warning { Some(GamutCheck::new(&composite_profile(doc), &pv.setup.profile, pv.gamut_threshold).map_err(cms_err)?) } else { None };
|
if pv.gamut_warning { Some(GamutCheck::new(&composite_profile(doc), &pv.setup.profile, pv.gamut_threshold).map_err(cms_err)?) } else { None };
|
||||||
let s = (size - 1) as f32;
|
let s = (size - 1) as f32;
|
||||||
for (i, px) in bytes.chunks_exact_mut(4).enumerate() {
|
for (i, px) in bytes.as_chunks_mut::<4>().0.iter_mut().enumerate() {
|
||||||
let rgb = [(i % size) as f32 / s, ((i / size) % size) as f32 / s, (i / (size * size)) as f32 / s];
|
let rgb = [(i % size) as f32 / s, ((i / size) % size) as f32 / s, (i / (size * size)) as f32 / s];
|
||||||
px[3] = if check.as_ref().is_some_and(|c| c.out_of_gamut(&rgb)) { 255 } else { 0 };
|
px[3] = if check.as_ref().is_some_and(|c| c.out_of_gamut(&rgb)) { 255 } else { 0 };
|
||||||
}
|
}
|
||||||
|
|
@ -1127,7 +1127,7 @@ mod tests {
|
||||||
let surf = doc.layers[0].surface_mut().unwrap();
|
let surf = doc.layers[0].surface_mut().unwrap();
|
||||||
let mut bytes = vec![0u8; r.width() as usize * r.height() as usize * 4];
|
let mut bytes = vec![0u8; r.width() as usize * r.height() as usize * 4];
|
||||||
let mut x = 1u32;
|
let mut x = 1u32;
|
||||||
for px in bytes.chunks_exact_mut(4) {
|
for px in bytes.as_chunks_mut::<4>().0 {
|
||||||
x ^= x << 13;
|
x ^= x << 13;
|
||||||
x ^= x >> 17;
|
x ^= x >> 17;
|
||||||
x ^= x << 5;
|
x ^= x << 5;
|
||||||
|
|
|
||||||
|
|
@ -158,7 +158,7 @@ fn colour_filters_use_and_record_tool_colours() {
|
||||||
let r = s.execute("filter.render.fibers", json!({"seed": 1})).unwrap();
|
let r = s.execute("filter.render.fibers", json!({"seed": 1})).unwrap();
|
||||||
assert_eq!(r["filter"]["foreground"], json!([1.0, 0.0, 0.0, 1.0]));
|
assert_eq!(r["filter"]["foreground"], json!([1.0, 0.0, 0.0, 1.0]));
|
||||||
let px = pixels(&s);
|
let px = pixels(&s);
|
||||||
for p in px.chunks_exact(4) {
|
for p in px.as_chunks::<4>().0 {
|
||||||
assert!(p[1] < 1e-2 && (p[0] + p[2] - 1.0).abs() < 2e-2, "{p:?}");
|
assert!(p[1] < 1e-2 && (p[0] + p[2] - 1.0).abs() < 2e-2, "{p:?}");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -234,7 +234,7 @@ mod tests {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn opaque(s: &Session) -> usize {
|
fn opaque(s: &Session) -> usize {
|
||||||
pixels(s).chunks_exact(4).filter(|p| p[3] > 0.05).count()
|
pixels(s).as_chunks::<4>().0.iter().filter(|p| p[3] > 0.05).count()
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
@ -294,7 +294,7 @@ mod tests {
|
||||||
let r = s.execute("filter.render.tree", json!({"newLayer": true, "baseTreeType": 1, "leavesAmount": 100})).unwrap();
|
let r = s.execute("filter.render.tree", json!({"newLayer": true, "baseTreeType": 1, "leavesAmount": 100})).unwrap();
|
||||||
assert_eq!(r["newLayer"], json!(true));
|
assert_eq!(r["newLayer"], json!(true));
|
||||||
let px = pixels(&s);
|
let px = pixels(&s);
|
||||||
let right = px.chunks_exact(4).enumerate().filter(|(i, p)| i % 160 >= 81 && p[3] > 0.0).count();
|
let right = px.as_chunks::<4>().0.iter().enumerate().filter(|(i, p)| i % 160 >= 81 && p[3] > 0.0).count();
|
||||||
assert_eq!(right, 0, "nothing drawn outside the selection");
|
assert_eq!(right, 0, "nothing drawn outside the selection");
|
||||||
assert!(opaque(&s) > 50);
|
assert!(opaque(&s) > 50);
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -56,7 +56,7 @@ pub(crate) fn warp_gray(s: &Surface, h: &Homography, interp: Interp) -> Surface
|
||||||
let b = w.content_bounds();
|
let b = w.content_bounds();
|
||||||
if !b.is_empty() {
|
if !b.is_empty() {
|
||||||
let px = w.read_region(b);
|
let px = w.read_region(b);
|
||||||
let flat: Vec<f32> = px.chunks_exact(2).map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect();
|
let flat: Vec<f32> = px.as_chunks::<2>().0.iter().map(|p| p[0] * p[1] + default * (1.0 - p[1])).collect();
|
||||||
out.write_region(b, &flat);
|
out.write_region(b, &flat);
|
||||||
}
|
}
|
||||||
out.prune();
|
out.prune();
|
||||||
|
|
|
||||||
|
|
@ -673,7 +673,7 @@ mod tests {
|
||||||
// Red pixels exist.
|
// Red pixels exist.
|
||||||
let c = t.cache.as_ref().unwrap();
|
let c = t.cache.as_ref().unwrap();
|
||||||
let r = c.content_bounds();
|
let r = c.content_bounds();
|
||||||
assert!(c.read_region(r).chunks_exact(4).any(|p| p[3] > 0.9 && p[0] > 0.9 && p[1] < 0.1));
|
assert!(c.read_region(r).as_chunks::<4>().0.iter().any(|p| p[3] > 0.9 && p[0] > 0.9 && p[1] < 0.1));
|
||||||
// The TySh we generated parses back to the same model.
|
// The TySh we generated parses back to the same model.
|
||||||
let back = photocraft_text::psd::text_layer_from_tysh(t.psd_raw.as_ref().unwrap(), 72.0).unwrap();
|
let back = photocraft_text::psd::text_layer_from_tysh(t.psd_raw.as_ref().unwrap(), 72.0).unwrap();
|
||||||
assert_eq!(back.text, "Hello");
|
assert_eq!(back.text, "Hello");
|
||||||
|
|
|
||||||
|
|
@ -385,7 +385,7 @@ pub fn optimize(px: &[[f32; 4]], bw: usize, rect: Rect, st: &WebSettings, icc: O
|
||||||
data.extend_from_slice(&[to8(q[0]), to8(q[1]), to8(q[2]), to8(q[3])][..k]);
|
data.extend_from_slice(&[to8(q[0]), to8(q[1]), to8(q[2]), to8(q[3])][..k]);
|
||||||
}
|
}
|
||||||
if preview {
|
if preview {
|
||||||
look = if alpha { data.clone() } else { data.chunks_exact(3).flat_map(|c| [c[0], c[1], c[2], 255]).collect() };
|
look = if alpha { data.clone() } else { data.as_chunks::<3>().0.iter().flat_map(|c| [c[0], c[1], c[2], 255]).collect() };
|
||||||
}
|
}
|
||||||
let layout = if alpha { photocraft_codecs::ChannelLayout::Rgba } else { photocraft_codecs::ChannelLayout::Rgb };
|
let layout = if alpha { photocraft_codecs::ChannelLayout::Rgba } else { photocraft_codecs::ChannelLayout::Rgb };
|
||||||
let meta = photocraft_codecs::Metadata { dpi: Some((dpi, dpi)), xmp: xmp.map(str::to_string), ..Default::default() };
|
let meta = photocraft_codecs::Metadata { dpi: Some((dpi, dpi)), xmp: xmp.map(str::to_string), ..Default::default() };
|
||||||
|
|
@ -412,7 +412,7 @@ pub fn optimize(px: &[[f32; 4]], bw: usize, rect: Rect, st: &WebSettings, icc: O
|
||||||
// The preview shows the compression artefacts.
|
// The preview shows the compression artefacts.
|
||||||
look = match photocraft_codecs::decode(&bytes) {
|
look = match photocraft_codecs::decode(&bytes) {
|
||||||
Ok(img) => img.convert(photocraft_codecs::ChannelLayout::Rgba, photocraft_codecs::SampleType::U8).data().to_vec(),
|
Ok(img) => img.convert(photocraft_codecs::ChannelLayout::Rgba, photocraft_codecs::SampleType::U8).data().to_vec(),
|
||||||
Err(_) => rgb.chunks_exact(3).flat_map(|c| [c[0], c[1], c[2], 255]).collect(),
|
Err(_) => rgb.as_chunks::<3>().0.iter().flat_map(|c| [c[0], c[1], c[2], 255]).collect(),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
(bytes, None)
|
(bytes, None)
|
||||||
|
|
|
||||||
|
|
@ -60,8 +60,8 @@ pub(crate) fn swap_to_le(bytes: &mut [u8], sample: SampleType) {
|
||||||
if cfg!(target_endian = "big") {
|
if cfg!(target_endian = "big") {
|
||||||
match sample {
|
match sample {
|
||||||
SampleType::U8 => {}
|
SampleType::U8 => {}
|
||||||
SampleType::U16 => bytes.chunks_exact_mut(2).for_each(|c| c.reverse()),
|
SampleType::U16 => bytes.as_chunks_mut::<2>().0.iter_mut().for_each(|c| c.reverse()),
|
||||||
SampleType::F32 => bytes.chunks_exact_mut(4).for_each(|c| c.reverse()),
|
SampleType::F32 => bytes.as_chunks_mut::<4>().0.iter_mut().for_each(|c| c.reverse()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -103,7 +103,7 @@ fn color_from(space: u16, c: [u16; 4]) -> Color {
|
||||||
|
|
||||||
fn decode_text(data: &[u8]) -> String {
|
fn decode_text(data: &[u8]) -> String {
|
||||||
let s = if data.len() >= 2 && data[0] == 0xFE && data[1] == 0xFF {
|
let s = if data.len() >= 2 && data[0] == 0xFE && data[1] == 0xFF {
|
||||||
let units: Vec<u16> = data[2..].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let units: Vec<u16> = data[2..].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
String::from_utf16_lossy(&units)
|
String::from_utf16_lossy(&units)
|
||||||
} else {
|
} else {
|
||||||
data.iter().map(|&c| c as char).collect()
|
data.iter().map(|&c| c as char).collect()
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,7 @@ use photocraft_psd::layer::BlendingRanges;
|
||||||
/// `brst` (channel blending restrictions): a list of big-endian u32 channel indices left out of
|
/// `brst` (channel blending restrictions): a list of big-endian u32 channel indices left out of
|
||||||
/// blending → a bit mask (bit `i` = channel `i`; indices above 31 are ignored).
|
/// blending → a bit mask (bit `i` = channel `i`; indices above 31 are ignored).
|
||||||
pub fn parse_brst(data: &[u8]) -> u32 {
|
pub fn parse_brst(data: &[u8]) -> u32 {
|
||||||
data.chunks_exact(4).map(|c| u32::from_be_bytes([c[0], c[1], c[2], c[3]])).filter(|&i| i < 32).fold(0, |m, i| m | 1 << i)
|
data.as_chunks::<4>().0.iter().map(|c| u32::from_be_bytes([c[0], c[1], c[2], c[3]])).filter(|&i| i < 32).fold(0, |m, i| m | 1 << i)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Inverse of [`parse_brst`]; `None` when every channel blends (no block).
|
/// Inverse of [`parse_brst`]; `None` when every channel blends (no block).
|
||||||
|
|
|
||||||
|
|
@ -42,7 +42,7 @@ pub(crate) fn display_info(channels: &[&AlphaChannel]) -> Vec<u8> {
|
||||||
/// Applies a DisplayInfo resource (`versioned` = 1077) to the imported channels in order.
|
/// Applies a DisplayInfo resource (`versioned` = 1077) to the imported channels in order.
|
||||||
pub(crate) fn apply_display_info(data: &[u8], versioned: bool, channels: &mut [AlphaChannel]) {
|
pub(crate) fn apply_display_info(data: &[u8], versioned: bool, channels: &mut [AlphaChannel]) {
|
||||||
let body = if versioned { data.get(4..).unwrap_or(&[]) } else { data };
|
let body = if versioned { data.get(4..).unwrap_or(&[]) } else { data };
|
||||||
for (c, rec) in channels.iter_mut().zip(body.chunks_exact(14)) {
|
for (c, rec) in channels.iter_mut().zip(body.as_chunks::<14>().0) {
|
||||||
let u = |i: usize| u16::from_be_bytes([rec[i], rec[i + 1]]);
|
let u = |i: usize| u16::from_be_bytes([rec[i], rec[i + 1]]);
|
||||||
let comps = [u(2), u(4), u(6), u(8)];
|
let comps = [u(2), u(4), u(6), u(8)];
|
||||||
let color = decode_color(u(0), comps);
|
let color = decode_color(u(0), comps);
|
||||||
|
|
|
||||||
|
|
@ -148,7 +148,9 @@ pub fn merged_composite(file: &PsdFile) -> Result<Vec<[f32; 4]>, IoError> {
|
||||||
let unmatte = file.merged_has_alpha();
|
let unmatte = file.merged_has_alpha();
|
||||||
return Ok(img
|
return Ok(img
|
||||||
.data
|
.data
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
.map(|p| {
|
.map(|p| {
|
||||||
let mut v: [f32; 4] = std::array::from_fn(|i| f32::from(p[i]) / 255.0);
|
let mut v: [f32; 4] = std::array::from_fn(|i| f32::from(p[i]) / 255.0);
|
||||||
if unmatte {
|
if unmatte {
|
||||||
|
|
|
||||||
|
|
@ -43,7 +43,7 @@ impl<'a> Rd<'a> {
|
||||||
fn unicode(&mut self) -> Option<String> {
|
fn unicode(&mut self) -> Option<String> {
|
||||||
let n = self.u32()? as usize;
|
let n = self.u32()? as usize;
|
||||||
let raw = self.take(n.checked_mul(2)?)?;
|
let raw = self.take(n.checked_mul(2)?)?;
|
||||||
let units: Vec<u16> = raw.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let units: Vec<u16> = raw.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
Some(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string())
|
Some(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -351,7 +351,7 @@ fn unicode_names(data: &[u8]) -> Vec<String> {
|
||||||
let n = u32::from_be_bytes([data[at], data[at + 1], data[at + 2], data[at + 3]]) as usize;
|
let n = u32::from_be_bytes([data[at], data[at + 1], data[at + 2], data[at + 3]]) as usize;
|
||||||
at += 4;
|
at += 4;
|
||||||
let Some(b) = data.get(at..at + n * 2) else { break };
|
let Some(b) = data.get(at..at + n * 2) else { break };
|
||||||
let units: Vec<u16> = b.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let units: Vec<u16> = b.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
out.push(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string());
|
out.push(String::from_utf16_lossy(&units).trim_end_matches('\0').to_string());
|
||||||
at += n * 2;
|
at += n * 2;
|
||||||
}
|
}
|
||||||
|
|
@ -549,7 +549,9 @@ pub fn psd_to_document(file: &PsdFile) -> (Document, Vec<String>) {
|
||||||
let mut s = Surface::new(fmt);
|
let mut s = Surface::new(fmt);
|
||||||
let vals: Vec<f32> = img
|
let vals: Vec<f32> = img
|
||||||
.data
|
.data
|
||||||
.chunks_exact(4)
|
.as_chunks::<4>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
.flat_map(|p| {
|
.flat_map(|p| {
|
||||||
let v = photocraft_raster::from_rgba(&fmt, [p[0], p[1], p[2], p[3]].map(|x| f32::from(x) / 255.0));
|
let v = photocraft_raster::from_rgba(&fmt, [p[0], p[1], p[2], p[3]].map(|x| f32::from(x) / 255.0));
|
||||||
v.into_iter()
|
v.into_iter()
|
||||||
|
|
|
||||||
|
|
@ -119,7 +119,7 @@ fn layered_to_png_warns_flatten() {
|
||||||
// Composite equals our flatten.
|
// Composite equals our flatten.
|
||||||
let flat = photocraft_compose::flatten(&d).px;
|
let flat = photocraft_compose::flatten(&d).px;
|
||||||
let s = back.layers[0].surface().unwrap();
|
let s = back.layers[0].surface().unwrap();
|
||||||
let px: Vec<[f32; 4]> = s.read_region(back.bounds()).chunks_exact(4).map(|p| [p[0], p[1], p[2], p[3]]).collect();
|
let px: Vec<[f32; 4]> = s.read_region(back.bounds()).as_chunks::<4>().0.iter().map(|p| [p[0], p[1], p[2], p[3]]).collect();
|
||||||
assert!(max_diff(&px, &flat) <= 1.0 / 255.0 + 1e-4);
|
assert!(max_diff(&px, &flat) <= 1.0 / 255.0 + 1e-4);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -88,7 +88,7 @@ impl<'de> Deserialize<'de> for GrayTile {
|
||||||
let data: Vec<u16> = match t.data {
|
let data: Vec<u16> = match t.data {
|
||||||
DataIn::B64(s) => {
|
DataIn::B64(s) => {
|
||||||
let b = b64_decode(&s).ok_or_else(|| D::Error::custom("invalid base64 in tile data"))?;
|
let b = b64_decode(&s).ok_or_else(|| D::Error::custom("invalid base64 in tile data"))?;
|
||||||
b.chunks_exact(2).map(|c| u16::from_le_bytes([c[0], c[1]])).collect()
|
b.as_chunks::<2>().0.iter().map(|c| u16::from_le_bytes([c[0], c[1]])).collect()
|
||||||
}
|
}
|
||||||
DataIn::Floats(v) => v.iter().map(|&x| q16(x)).collect(),
|
DataIn::Floats(v) => v.iter().map(|&x| q16(x)).collect(),
|
||||||
};
|
};
|
||||||
|
|
|
||||||
|
|
@ -289,7 +289,7 @@ impl BlendingRanges {
|
||||||
}
|
}
|
||||||
/// Parsed entries (incomplete trailing bytes are ignored).
|
/// Parsed entries (incomplete trailing bytes are ignored).
|
||||||
pub fn ranges(&self) -> Vec<BlendRange> {
|
pub fn ranges(&self) -> Vec<BlendRange> {
|
||||||
self.data.chunks_exact(8).map(|c| BlendRange { source: [c[0], c[1], c[2], c[3]], dest: [c[4], c[5], c[6], c[7]] }).collect()
|
self.data.as_chunks::<8>().0.iter().map(|c| BlendRange { source: [c[0], c[1], c[2], c[3]], dest: [c[4], c[5], c[6], c[7]] }).collect()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -115,7 +115,9 @@ impl PathData {
|
||||||
return Err(PsdError::LimitExceeded("path records"));
|
return Err(PsdError::LimitExceeded("path records"));
|
||||||
}
|
}
|
||||||
let records = data
|
let records = data
|
||||||
.chunks_exact(RECORD_LEN)
|
.as_chunks::<RECORD_LEN>()
|
||||||
|
.0
|
||||||
|
.iter()
|
||||||
.map(|c| {
|
.map(|c| {
|
||||||
let mut d = [0u8; 24];
|
let mut d = [0u8; 24];
|
||||||
d.copy_from_slice(&c[2..]);
|
d.copy_from_slice(&c[2..]);
|
||||||
|
|
|
||||||
|
|
@ -105,7 +105,7 @@ fn read_pattern(r: &mut Rd) -> Result<PsdPattern> {
|
||||||
if n > 65_536 {
|
if n > 65_536 {
|
||||||
return Err(PsdError::LimitExceeded("pattern name length"));
|
return Err(PsdError::LimitExceeded("pattern name length"));
|
||||||
}
|
}
|
||||||
let units: Vec<u16> = r.take(n * 2)?.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let units: Vec<u16> = r.take(n * 2)?.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
let name = String::from_utf16_lossy(&units).trim_end_matches('\0').to_string();
|
let name = String::from_utf16_lossy(&units).trim_end_matches('\0').to_string();
|
||||||
let idl = r.u8()? as usize;
|
let idl = r.u8()? as usize;
|
||||||
let id = String::from_utf8_lossy(r.take(idl)?).to_string();
|
let id = String::from_utf8_lossy(r.take(idl)?).to_string();
|
||||||
|
|
|
||||||
|
|
@ -12,12 +12,12 @@ use crate::layer::{CHANNEL_REAL_USER_MASK, CHANNEL_TRANSPARENCY, CHANNEL_USER_MA
|
||||||
|
|
||||||
/// Interprets planar big-endian bytes as u16 samples.
|
/// Interprets planar big-endian bytes as u16 samples.
|
||||||
pub fn samples_u16(bytes: &[u8]) -> Vec<u16> {
|
pub fn samples_u16(bytes: &[u8]) -> Vec<u16> {
|
||||||
bytes.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect()
|
bytes.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Interprets planar big-endian bytes as f32 samples.
|
/// Interprets planar big-endian bytes as f32 samples.
|
||||||
pub fn samples_f32(bytes: &[u8]) -> Vec<f32> {
|
pub fn samples_f32(bytes: &[u8]) -> Vec<f32> {
|
||||||
bytes.chunks_exact(4).map(|c| f32::from_be_bytes([c[0], c[1], c[2], c[3]])).collect()
|
bytes.as_chunks::<4>().0.iter().map(|c| f32::from_be_bytes([c[0], c[1], c[2], c[3]])).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Encodes u16 samples as big-endian bytes.
|
/// Encodes u16 samples as big-endian bytes.
|
||||||
|
|
|
||||||
|
|
@ -185,7 +185,7 @@ impl ImageResource {
|
||||||
if !d.len().is_multiple_of(2) {
|
if !d.len().is_multiple_of(2) {
|
||||||
Err(PsdError::invalid("layer group info has odd length"))
|
Err(PsdError::invalid("layer group info has odd length"))
|
||||||
} else {
|
} else {
|
||||||
Ok(ResourceData::LayerGroupInfo(d.chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect()))
|
Ok(ResourceData::LayerGroupInfo(d.as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect()))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
ids::THUMBNAIL | ids::THUMBNAIL_PS4 => Ok(ResourceData::Thumbnail(d)),
|
ids::THUMBNAIL | ids::THUMBNAIL_PS4 => Ok(ResourceData::Thumbnail(d)),
|
||||||
|
|
|
||||||
|
|
@ -277,13 +277,13 @@ impl Surface {
|
||||||
match (fmt.mode, fmt.sample, fmt.alpha) {
|
match (fmt.mode, fmt.sample, fmt.alpha) {
|
||||||
(ColorMode::Rgb, SampleType::U8, true) => {
|
(ColorMode::Rgb, SampleType::U8, true) => {
|
||||||
let src = &t.data[base..base + dst.len() * 4];
|
let src = &t.data[base..base + dst.len() * 4];
|
||||||
for (d, s) in dst.iter_mut().zip(src.chunks_exact(4)) {
|
for (d, s) in dst.iter_mut().zip(src.as_chunks::<4>().0) {
|
||||||
*d = [s[0] as f32 / 255.0, s[1] as f32 / 255.0, s[2] as f32 / 255.0, s[3] as f32 / 255.0];
|
*d = [s[0] as f32 / 255.0, s[1] as f32 / 255.0, s[2] as f32 / 255.0, s[3] as f32 / 255.0];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
(ColorMode::Grayscale, SampleType::U8, true) => {
|
(ColorMode::Grayscale, SampleType::U8, true) => {
|
||||||
let src = &t.data[base..base + dst.len() * 2];
|
let src = &t.data[base..base + dst.len() * 2];
|
||||||
for (d, s) in dst.iter_mut().zip(src.chunks_exact(2)) {
|
for (d, s) in dst.iter_mut().zip(src.as_chunks::<2>().0) {
|
||||||
let g = s[0] as f32 / 255.0;
|
let g = s[0] as f32 / 255.0;
|
||||||
*d = [g, g, g, s[1] as f32 / 255.0];
|
*d = [g, g, g, s[1] as f32 / 255.0];
|
||||||
}
|
}
|
||||||
|
|
@ -324,7 +324,7 @@ impl Surface {
|
||||||
Some(t) if rgba8 => {
|
Some(t) if rgba8 => {
|
||||||
let base = (((y - tc.ty * TILE_SIZE) as usize) * TILE_SIZE as usize + (tr.x0 - tc.tx * TILE_SIZE) as usize) * 4;
|
let base = (((y - tc.ty * TILE_SIZE) as usize) * TILE_SIZE as usize + (tr.x0 - tc.tx * TILE_SIZE) as usize) * 4;
|
||||||
let len = dst.len();
|
let len = dst.len();
|
||||||
for (d, s) in dst.iter_mut().zip(t.data[base..base + len * 4].chunks_exact(4)) {
|
for (d, s) in dst.iter_mut().zip(t.data[base..base + len * 4].as_chunks::<4>().0) {
|
||||||
*d = [s[0], s[1], s[2], s[3]];
|
*d = [s[0], s[1], s[2], s[3]];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -206,7 +206,7 @@ impl Parser<'_> {
|
||||||
|
|
||||||
fn decode_string(raw: &[u8]) -> String {
|
fn decode_string(raw: &[u8]) -> String {
|
||||||
if raw.len() >= 2 && raw[0] == 0xFE && raw[1] == 0xFF {
|
if raw.len() >= 2 && raw[0] == 0xFE && raw[1] == 0xFF {
|
||||||
let u: Vec<u16> = raw[2..].chunks_exact(2).map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
let u: Vec<u16> = raw[2..].as_chunks::<2>().0.iter().map(|c| u16::from_be_bytes([c[0], c[1]])).collect();
|
||||||
String::from_utf16_lossy(&u)
|
String::from_utf16_lossy(&u)
|
||||||
} else {
|
} else {
|
||||||
raw.iter().map(|&c| c as char).collect()
|
raw.iter().map(|&c| c as char).collect()
|
||||||
|
|
|
||||||
|
|
@ -192,9 +192,9 @@ pub fn write_style_sheets(tysh: &[u8], layer: &TextLayer, styles: &TextStyles, d
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
let raw = crate::engine_data::write(&e);
|
let raw = crate::engine_data::write(&e);
|
||||||
match t.text.items.iter_mut().find(|(k, _)| k.is("EngineData")) {
|
{
|
||||||
Some(item) => item.1 = photocraft_psd::descriptor::Value::RawData(raw),
|
let item = t.text.items.iter_mut().find(|(k, _)| k.is("EngineData"))?;
|
||||||
None => return None,
|
item.1 = photocraft_psd::descriptor::Value::RawData(raw)
|
||||||
}
|
}
|
||||||
Some(write_tysh(&t))
|
Some(write_tysh(&t))
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -272,12 +272,12 @@ fn multicolor_runs() {
|
||||||
let (l, r) = e.render(&t, 72.0, PixelFormat::RGBA8);
|
let (l, r) = e.render(&t, 72.0, PixelFormat::RGBA8);
|
||||||
assert_eq!(l.glyphs.len(), 2);
|
assert_eq!(l.glyphs.len(), 2);
|
||||||
let px = r.surface.read_region(r.rect);
|
let px = r.surface.read_region(r.rect);
|
||||||
let opaque: Vec<&[f32]> = px.chunks_exact(4).filter(|p| p[3] > 0.99).collect();
|
let opaque: Vec<&[f32; 4]> = px.as_chunks::<4>().0.iter().filter(|p| p[3] > 0.99).collect();
|
||||||
assert!(opaque.iter().any(|p| p[0] > 0.99 && p[2] < 0.01));
|
assert!(opaque.iter().any(|p| p[0] > 0.99 && p[2] < 0.01));
|
||||||
assert!(opaque.iter().any(|p| p[2] > 0.99 && p[0] < 0.01));
|
assert!(opaque.iter().any(|p| p[2] > 0.99 && p[0] < 0.01));
|
||||||
// CMYK target keeps colour in the document model.
|
// CMYK target keeps colour in the document model.
|
||||||
let (_, rc) = e.render(&t, 72.0, PixelFormat::CMYKA8);
|
let (_, rc) = e.render(&t, 72.0, PixelFormat::CMYKA8);
|
||||||
assert!(rc.surface.read_region(rc.rect).chunks_exact(5).any(|p| p[4] > 0.99 && p[1] > 0.9 && p[2] > 0.9));
|
assert!(rc.surface.read_region(rc.rect).as_chunks::<5>().0.iter().any(|p| p[4] > 0.99 && p[1] > 0.9 && p[2] > 0.9));
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
|
|
||||||
|
|
@ -481,7 +481,7 @@ mod tests {
|
||||||
let mut b = BrushSettings { size: 400.0, ..Default::default() };
|
let mut b = BrushSettings { size: 400.0, ..Default::default() };
|
||||||
let px = preview_pixels(&b, 120, 40, [1.0, 0.0, 0.0, 1.0]);
|
let px = preview_pixels(&b, 120, 40, [1.0, 0.0, 0.0, 1.0]);
|
||||||
assert_eq!(px.len(), 120 * 40 * 4);
|
assert_eq!(px.len(), 120 * 40 * 4);
|
||||||
let covered = px.chunks_exact(4).filter(|p| p[3] > 128).count();
|
let covered = px.as_chunks::<4>().0.iter().filter(|p| p[3] > 128).count();
|
||||||
assert!(covered > 200 && covered < 120 * 40 / 2, "{covered}");
|
assert!(covered > 200 && covered < 120 * 40 / 2, "{covered}");
|
||||||
// Dynamics change the preview.
|
// Dynamics change the preview.
|
||||||
b.scattering.enabled = true;
|
b.scattering.enabled = true;
|
||||||
|
|
|
||||||
|
|
@ -341,7 +341,7 @@ impl Perf {
|
||||||
/// Straight-alpha f32 RGBA (sRGB-encoded) → premultiplied RGBA8, split across threads on native.
|
/// Straight-alpha f32 RGBA (sRGB-encoded) → premultiplied RGBA8, split across threads on native.
|
||||||
pub fn premultiply_rgba8(px: &[[f32; 4]]) -> Vec<u8> {
|
pub fn premultiply_rgba8(px: &[[f32; 4]]) -> Vec<u8> {
|
||||||
fn convert(src: &[[f32; 4]], dst: &mut [u8]) {
|
fn convert(src: &[[f32; 4]], dst: &mut [u8]) {
|
||||||
for (o, p) in dst.chunks_exact_mut(4).zip(src) {
|
for (o, p) in dst.as_chunks_mut::<4>().0.iter_mut().zip(src) {
|
||||||
let a = p[3].clamp(0.0, 1.0);
|
let a = p[3].clamp(0.0, 1.0);
|
||||||
o[0] = (p[0].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8;
|
o[0] = (p[0].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8;
|
||||||
o[1] = (p[1].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8;
|
o[1] = (p[1].clamp(0.0, 1.0) * a * 255.0 + 0.5) as u8;
|
||||||
|
|
|
||||||
|
|
@ -686,7 +686,7 @@ fn draw_mesh(d: &LiquifyDialog, painter: &egui::Painter, area: ERect) {
|
||||||
pts.push([pa[0] + (pb[0] - pa[0]) * t, pa[1] + (pb[1] - pa[1]) * t]);
|
pts.push([pa[0] + (pb[0] - pa[0]) * t, pa[1] + (pb[1] - pa[1]) * t]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for seg in pts.chunks_exact(2) {
|
for seg in pts.as_chunks::<2>().0 {
|
||||||
painter.line_segment([to_screen(d, area, seg[0]), to_screen(d, area, seg[1])], stroke);
|
painter.line_segment([to_screen(d, area, seg[0]), to_screen(d, area, seg[1])], stroke);
|
||||||
}
|
}
|
||||||
k += 1;
|
k += 1;
|
||||||
|
|
|
||||||
|
|
@ -90,9 +90,7 @@ pub fn show(app: &mut PhotocraftApp, ctx: &egui::Context) {
|
||||||
s,
|
s,
|
||||||
m.id,
|
m.id,
|
||||||
m.label.trim_end_matches('…').to_string(),
|
m.label.trim_end_matches('…').to_string(),
|
||||||
Some(path)
|
Some(path + &m.shortcut.map(|s| format!(" {}", crate::shortcuts::pretty(&s))).unwrap_or_default()),
|
||||||
.filter(|_| true)
|
|
||||||
.map(|p| p + &m.shortcut.map(|s| format!(" {}", crate::shortcuts::pretty(&s))).unwrap_or_default()),
|
|
||||||
m.enabled,
|
m.enabled,
|
||||||
))
|
))
|
||||||
})
|
})
|
||||||
|
|
|
||||||
|
|
@ -26,7 +26,7 @@ fn compute_histograms(doc: &Document, hide: LayerId) -> Histograms {
|
||||||
}
|
}
|
||||||
let img = photocraft_compose::thumbnail(&d, 384);
|
let img = photocraft_compose::thumbnail(&d, 384);
|
||||||
let mut h = [[0u32; 256]; 4];
|
let mut h = [[0u32; 256]; 4];
|
||||||
for p in img.pixels.chunks_exact(4) {
|
for p in img.pixels.as_chunks::<4>().0 {
|
||||||
if p[3] == 0 {
|
if p[3] == 0 {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue