Rasterize: Color Model is a dropdown of the document's model, Grayscale and Bitmap (#5660)

This commit is contained in:
Don Omondi
2026-11-05 11:52:25 +07:00
committed by bflatastic
parent ba1757d603
commit 44b828629d
+71 -1
View File
@@ -21,7 +21,9 @@ pub(super) const SPEC: DialogSpec = DialogSpec {
// Area Type Options: a Row Gutter still as it opened, on rows without a gutter of their own,
// follows the Gutter as it is changed.
let linked = d.fields.get("__rowGutterLinked").is_some() && d.fields.get("__rowGutterLinked") == d.fields.get("rowGutter");
form::param_fields(ui, d, &|k| lengths.contains(&k), &|k| choices(&command, k), &rank, app.session.general_unit());
let cmyk = app.session.active().is_some_and(|s| s.doc.color_mode == vectorcraft_doc::ColorMode::Cmyk);
let choices = |k: &str| rasterize_color_models(&command, k, cmyk).or_else(|| choices(&command, k));
form::param_fields(ui, d, &|k| lengths.contains(&k), &choices, &rank, app.session.general_unit());
if linked
&& d.fields.get("rowGutter") == d.fields.get("__rowGutterLinked")
&& let Some(g) = d.fields.get("gutter").cloned()
@@ -138,6 +140,19 @@ fn choices(command: &str, key: &str) -> Option<form::Choices> {
}
}
/// Object › Rasterize › Color Model: the values `object.rasterize` takes, the document's own
/// colour model first (#5660).
fn rasterize_color_models(command: &str, key: &str, cmyk: bool) -> Option<form::Choices> {
match (command, key) {
("object.rasterize", "colorModel") => Some(if cmyk { RASTERIZE_CMYK } else { RASTERIZE_RGB }),
_ => None,
}
}
/// Object › Rasterize › Color Model in an RGB and in a CMYK document.
const RASTERIZE_RGB: form::Choices = &[("RGB", "rgb"), ("Grayscale", "grayscale"), ("Bitmap", "bitmap")];
const RASTERIZE_CMYK: form::Choices = &[("CMYK", "cmyk"), ("Grayscale", "grayscale"), ("Bitmap", "bitmap")];
/// Type on a Path Options › Align to Path.
const PATH_ALIGN: form::Choices = &[("Ascender", "ascender"), ("Descender", "descender"), ("Center", "center"), ("Baseline", "baseline")];
@@ -287,6 +302,61 @@ mod tests {
assert_eq!(t.area.flow, vectorcraft_doc::TextFlow::Rows);
}
/// Object › Rasterize › Color Model is a dropdown of the models `object.rasterize` takes, the
/// document's own first (#5660): every value runs, and picking Grayscale rasterizes in grays.
#[test]
fn rasterize_color_model_is_a_dropdown_of_the_models_the_command_takes() {
use egui::accesskit::Role;
use egui_kittest::kittest::Queryable;
for (mode, own) in [("rgb", "RGB"), ("cmyk", "CMYK")] {
let models = rasterize_color_models("object.rasterize", "colorModel", mode == "cmyk").unwrap();
assert_eq!(models.first(), Some(&(own, mode)), "the document's own model first");
for (_, value) in models {
let mut s = Session::new();
s.execute("file.new", &json!({"width": 100, "height": 100, "colorMode": mode})).unwrap();
s.execute("shape.rectangle", &json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap();
s.execute("object.rasterize", &json!({"ppi": 72, "colorModel": value})).unwrap_or_else(|e| panic!("{mode} {value}: {e}"));
}
}
assert!(rasterize_color_models("object.rasterize", "background", false).is_none());
assert!(rasterize_color_models("document.rasterEffectsSettings", "colorModel", false).is_none());
let mut app = VectorcraftApp::new(Session::new(), Default::default());
app.run("file.new", json!({"width": 200, "height": 200})).unwrap();
let id = app.run("shape.rectangle", json!({"x": 10, "y": 10, "width": 20, "height": 20})).unwrap()["id"].as_u64().unwrap();
app.run("paint.setFill", json!({"color": "#ff0000", "ids": [id]})).unwrap();
app.run("select.set", json!({"ids": [id]})).unwrap();
crate::menus::invoke(&mut app, "object.rasterize", json!({}));
assert_eq!(app.ui.dialog.as_ref().unwrap().str("colorModel"), "rgb");
let mut fonts = false;
let mut h = egui_kittest::Harness::builder().with_size(egui::vec2(1100.0, 900.0)).build_ui_state(
move |ui, app: &mut VectorcraftApp| {
if !std::mem::replace(&mut fonts, true) {
crate::theme::install_fonts(ui.ctx());
return;
}
crate::dialogs::show(app, ui.ctx());
},
app,
);
h.run_steps(5);
assert!(h.query_by_role_and_label(Role::TextInput, "Color Model:").is_none(), "not a text field");
h.get_by_role_and_label(Role::ComboBox, "Color Model:").click();
h.run_steps(3);
h.get_by_label("Grayscale").click();
h.run_steps(3);
assert_eq!(h.state().ui.dialog.as_ref().unwrap().str("colorModel"), "grayscale");
let app = h.state_mut();
crate::dialogs::confirm(app).unwrap();
let st = app.session.active().unwrap();
let key = st.selection.objects.iter().find_map(|id| match st.doc.node(*id).map(|n| &n.kind) {
Some(NodeKind::Image(i)) => Some(i.key.clone()),
_ => None,
});
let img = image::load_from_memory(&st.doc.images[&key.expect("the rectangle became an image")].bytes).unwrap().to_rgba8();
let p = img.get_pixel(img.width() / 2, img.height() / 2).0;
assert!(p[0] == p[1] && p[1] == p[2] && p[0] < 128, "red in grayscale: {p:?}");
}
/// Graph Type › Value Axis is a dropdown of the values `graph.setType` takes, and OK puts the
/// value axis on the side picked.
#[test]