mirror of
https://github.com/storytold/photocraft.git
synced 2026-11-12 21:23:02 +00:00
Merge pull request #9246 from DuBearte/fix/9236-cmyk-split-channels
fix(engine): CMYK Split Channels reads the composite's exact inks (#9236)
This commit is contained in:
2 files changed
+40
-1
No files matched your search
@@ -72,8 +72,21 @@ pub(super) fn split(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
}
|
||||
let doc = s.documents()[idx].doc.clone();
|
||||
let area = doc.bounds();
|
||||
let (px, n) = native_pixels(&doc, None)?;
|
||||
let mode = edit_mode(&doc);
|
||||
// A CMYK composite's channels are its inks: mixed on ink values where the stack allows, since
|
||||
// a trip through RGB moves them by a few levels (#9236).
|
||||
let inks = if mode == ColorMode::Cmyk { photocraft_compose::cmyk::render_cmyk(&doc, doc.bounds()) } else { None };
|
||||
let (px, n) = match inks {
|
||||
Some(buf) => {
|
||||
let n = doc.pixel_format().channels();
|
||||
let px: Vec<f32> = buf.px.iter().flat_map(|p| p.iter().copied().take(n)).collect();
|
||||
if px.len() != buf.px.len() * n {
|
||||
return Err(EngineError::Other(format!("Split Channels: an ink pixel has fewer than {n} values")));
|
||||
}
|
||||
(px, n)
|
||||
}
|
||||
None => native_pixels(&doc, None)?,
|
||||
};
|
||||
let names = color_names(mode);
|
||||
let short = |name: &str| name.chars().next().map(|c| c.to_ascii_uppercase().to_string()).unwrap_or_default();
|
||||
let mut docs: Vec<Document> = Vec::new();
|
||||
|
||||
@@ -898,6 +898,32 @@ fn split_and_merge_channels() {
|
||||
assert!(s.execute("channel.merge", json!({"mode": "cmyk"})).is_err());
|
||||
}
|
||||
|
||||
/// #9236: CMYK channels split into greyscale shown as the Channels panel shows them (white
|
||||
/// paper, dark ink), and merge back into the same inks.
|
||||
#[test]
|
||||
fn split_and_merge_cmyk_keep_ink_dark() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", json!({"width": 40, "height": 20, "mode": "cmyk", "background": "white"})).unwrap();
|
||||
// Rich black (#8359): its inks don't survive a trip through RGB, so the old path fails here.
|
||||
let rgb = photocraft_color::convert::cmyk_to_rgb([1.0, 1.0, 1.0, 0.0]).map(|c| c.clamp(0.0, 1.0));
|
||||
s.execute("tools.setColors", json!({"foreground": rgb, "foregroundCmyk": [1.0, 1.0, 1.0, 0.0]})).unwrap();
|
||||
s.execute("select.rect", json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap();
|
||||
s.execute("edit.fillForeground", json!({})).unwrap();
|
||||
s.execute("select.deselect", json!({})).unwrap();
|
||||
let (ink, paper) = (px(&s, 1, 1), px(&s, 30, 1));
|
||||
assert!(ink[..3].iter().all(|v| *v > 0.99) && paper[..4].iter().all(|v| *v < 0.01), "{ink:?} {paper:?}");
|
||||
s.execute("channel.split", json!({})).unwrap();
|
||||
assert_eq!(s.documents().len(), 4);
|
||||
for (i, ink) in ink[..4].iter().enumerate() {
|
||||
let at = |x| s.documents()[i].doc.layers[0].surface().unwrap().pixel(x, 1)[0];
|
||||
assert!((at(1) - (1.0 - ink)).abs() < 0.003, "channel {i}: {} for ink {ink}", at(1));
|
||||
assert!((at(30) - 1.0).abs() < 0.003, "channel {i}: paper is white, got {}", at(30));
|
||||
}
|
||||
s.execute("channel.merge", json!({"mode": "cmyk", "documents": [0, 1, 2, 3]})).unwrap();
|
||||
let back = px(&s, 1, 1);
|
||||
assert!(back[..4].iter().zip(&ink[..4]).all(|(a, b)| (a - b).abs() < 0.003), "{back:?} vs {ink:?}");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn cmyk_split_and_merge_use_tone() {
|
||||
// #5787: Split Channels of a white CMYK image gives white grayscale documents, and merging
|
||||
|
||||
Reference in new issue
Block a user