Merge pull request #1750 from Messhias/feat/394-black-output
Part of #394: Appearance of Black › Printing / Exporting
This commit is contained in:
commit
327170a8e8
|
|
@ -175,6 +175,8 @@ struct RasterOptions {
|
|||
layers: Option<bool>,
|
||||
max_editability: Option<bool>,
|
||||
hidden_layers: Option<bool>,
|
||||
/// Appearance of Black › Printing / Exporting (`prefs.blackOutput`); agents can set it here too.
|
||||
rich_black: Option<bool>,
|
||||
}
|
||||
|
||||
impl RasterOptions {
|
||||
|
|
@ -239,6 +241,7 @@ impl RasterOptions {
|
|||
hidden_layers: self.hidden_layers.unwrap_or(false),
|
||||
embed_icc,
|
||||
},
|
||||
rich_black: self.rich_black.unwrap_or(false),
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,14 +11,17 @@ use crate::DocState;
|
|||
|
||||
use super::super::*;
|
||||
use super::encode::single_artboard;
|
||||
use super::{ARTBOARD_PARAMS, Format, default_name, encode, encode_all, encode_with_warnings, merge, writable, write_encoded, write_or_return};
|
||||
use super::{
|
||||
ARTBOARD_PARAMS, Format, default_name, encode, encode_all, encode_with_warnings, merge, with_black_output, writable, write_encoded,
|
||||
write_or_return,
|
||||
};
|
||||
|
||||
pub(super) fn serialize(s: &mut Session, p: &Value) -> Result<Value> {
|
||||
let f = writable("document.serialize", Some(str_param(p, "format").unwrap_or("vectorcraft")), None)?;
|
||||
let expanded = expand_presets(s, "document.serialize", p)?;
|
||||
let p = &*expanded;
|
||||
let doc = &*source(s, f, p, "document.serialize")?;
|
||||
let enc = encode_all(doc, f.id, p)?;
|
||||
let p = with_black_output(s, &expanded);
|
||||
let doc = &*source(s, f, &p, "document.serialize")?;
|
||||
let enc = encode_all(doc, f.id, &p)?;
|
||||
let files = enc.named(doc, &default_name(doc, f.extensions[0]));
|
||||
let (main, linked) = files.split_at(enc.files.len());
|
||||
// Text formats come back as text; an SVG in UTF-16 or ISO 8859-1 also as its bytes.
|
||||
|
|
@ -50,9 +53,9 @@ pub(super) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
}
|
||||
let f = writable("document.export", str_param(p, "format"), path)?;
|
||||
let expanded = expand_presets(s, "document.export", p)?;
|
||||
let p = &*expanded;
|
||||
let doc = &*source(s, f, p, "document.export")?;
|
||||
let enc = encode_all(doc, f.id, p)?;
|
||||
let p = with_black_output(s, &expanded);
|
||||
let doc = &*source(s, f, &p, "document.export")?;
|
||||
let enc = encode_all(doc, f.id, &p)?;
|
||||
write_encoded(path, &default_name(doc, f.extensions[0]), doc, &enc, json!({ "format": f.id, "warnings": enc.warnings }))
|
||||
}
|
||||
|
||||
|
|
@ -185,11 +188,11 @@ pub(super) fn export_selection(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
let path = str_param(p, "path");
|
||||
let f = writable(C, str_param(p, "format"), path)?;
|
||||
let expanded = expand_presets(s, C, p)?;
|
||||
let p = &*expanded;
|
||||
let p = with_black_output(s, &expanded);
|
||||
let (d, bounds) = selection(s, C)?;
|
||||
// The encoder's warnings (options accepted but not applied, features approximated or left
|
||||
// out), as document.export reports them.
|
||||
let (bytes, warnings) = encode_with_warnings(&d, f.id, &without_artboards(p))?;
|
||||
let (bytes, warnings) = encode_with_warnings(&d, f.id, &without_artboards(&p))?;
|
||||
write_or_return(path, &bytes, json!({ "format": f.id, "warnings": warnings, "bounds": [bounds.x0, bounds.y0, bounds.width(), bounds.height()] }))
|
||||
}
|
||||
|
||||
|
|
@ -211,7 +214,8 @@ pub(super) fn export_for_office(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
return Err(bad(C, format!("no artboard {artboard} (0-based; the document has {})", doc.artboards.len())));
|
||||
}
|
||||
let background = if bool_or(p, "transparent", false) { "transparent" } else { "white" };
|
||||
let bytes = encode(doc, "png", &json!({ "ppi": ppi, "background": background, "artboard": artboard }))?;
|
||||
let opts = with_black_output(s, &json!({ "ppi": ppi, "background": background, "artboard": artboard }));
|
||||
let bytes = encode(doc, "png", &opts)?;
|
||||
// The pixel size, from the PNG header.
|
||||
let side = |at: usize| bytes.get(at..at + 4).and_then(|b| b.try_into().ok()).map_or(0, u32::from_be_bytes);
|
||||
write_or_return(path, &bytes, json!({ "width": side(16), "height": side(20) }))
|
||||
|
|
|
|||
|
|
@ -1052,6 +1052,12 @@ pub(crate) fn merge(mut a: Value, b: Value) -> Value {
|
|||
a
|
||||
}
|
||||
|
||||
/// Appearance of Black › Printing / Exporting (#394): Output All Blacks as Rich Black makes RGB
|
||||
/// raster exports draw pure CMYK black as RGB black (`richBlack` on the encoder params).
|
||||
pub(crate) fn with_black_output(s: &Session, p: &Value) -> Value {
|
||||
if s.prefs.black_output == "rich" { merge(p.clone(), json!({ "richBlack": true })) } else { p.clone() }
|
||||
}
|
||||
|
||||
/// A file name for bytes handed back without a path: the document's title with `ext`.
|
||||
pub(crate) fn default_name(doc: &vectorcraft_doc::Document, ext: &str) -> String {
|
||||
let stem = std::path::Path::new(&doc.title).file_stem().map(|s| s.to_string_lossy().into_owned()).filter(|s| !s.is_empty());
|
||||
|
|
|
|||
|
|
@ -15,7 +15,9 @@ use vectorcraft_geom::Rect;
|
|||
use super::super::*;
|
||||
use super::encode::single_artboard;
|
||||
use super::export::{isolated, without_artboards};
|
||||
use super::{ARTBOARD_PARAMS, ArtboardPick, Format, artboard_file_names, create_dir, encode, unique_file_names, writable, write_file};
|
||||
use super::{
|
||||
ARTBOARD_PARAMS, ArtboardPick, Format, artboard_file_names, create_dir, encode, unique_file_names, with_black_output, writable, write_file,
|
||||
};
|
||||
|
||||
const C: &str = "document.exportForScreens";
|
||||
|
||||
|
|
@ -363,6 +365,8 @@ pub(crate) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
if subfolders { format!("{}/{file}", r.folder) } else { file }
|
||||
};
|
||||
let mut out = Output::default();
|
||||
// Appearance of Black › Printing / Exporting for RGB raster rows.
|
||||
let write = |doc: &Document, format: &str, options: &Value| encode(doc, format, &with_black_output(s, options));
|
||||
if o.full_document {
|
||||
let stem = safe_name(&super::file_stem(&doc.title)).unwrap_or_else(|| "Untitled".into());
|
||||
// The bounds of all visible art, as the one artboard of the files that aren't PDFs.
|
||||
|
|
@ -376,7 +380,7 @@ pub(crate) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
// One page per artboard.
|
||||
let mut options = r.options.clone();
|
||||
options["range"] = json!("all");
|
||||
encode(&doc, "pdf", &options)?
|
||||
write(&doc, "pdf", &options)?
|
||||
} else {
|
||||
if whole.is_none() {
|
||||
let bounds =
|
||||
|
|
@ -385,7 +389,7 @@ pub(crate) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
}
|
||||
let Some(d) = whole.as_ref() else { continue };
|
||||
let region = d.artboards.first().map_or(Rect::ZERO, |a| a.rect);
|
||||
encode(d, r.format.id, &r.options_for(region, Some(0))?)?
|
||||
write(d, r.format.id, &r.options_for(region, Some(0))?)?
|
||||
};
|
||||
out.put(folder, o.zip, name, bytes)?;
|
||||
}
|
||||
|
|
@ -403,7 +407,7 @@ pub(crate) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
if !out.claim(&name) {
|
||||
continue;
|
||||
}
|
||||
let bytes = encode(&d, r.format.id, &r.options_for(bounds, Some(0))?)?;
|
||||
let bytes = write(&d, r.format.id, &r.options_for(bounds, Some(0))?)?;
|
||||
out.put(folder, o.zip, name, bytes)?;
|
||||
}
|
||||
}
|
||||
|
|
@ -420,7 +424,7 @@ pub(crate) fn export(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
if !out.claim(&name) {
|
||||
continue; // the same file from two identical rows
|
||||
}
|
||||
let bytes = encode(&doc, r.format.id, &r.options_for(region, Some(b))?)?;
|
||||
let bytes = write(&doc, r.format.id, &r.options_for(region, Some(b))?)?;
|
||||
out.put(folder, o.zip, name, bytes)?;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -106,6 +106,59 @@ fn screens_and_rasterize_take_anti_aliasing() {
|
|||
assert!(s.execute("object.rasterize", &json!({"antiAlias": "fuzzy"})).is_err());
|
||||
}
|
||||
|
||||
/// Appearance of Black › Printing / Exporting (#394): Output All Blacks as Rich Black makes an
|
||||
/// RGB PNG of a CMYK document draw pure black ink as RGB black; Accurately (the default) shows it
|
||||
/// through the CMYK profile. `blackOnScreen` does not change the export; a rich black is the same
|
||||
/// either way.
|
||||
#[test]
|
||||
fn black_output_rich_draws_pure_cmyk_black_as_rgb_black_in_png() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 20, "height": 20, "colorMode": "cmyk"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": {"c": 0, "m": 0, "y": 0, "k": 1}})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap();
|
||||
let centre = |s: &mut Session| {
|
||||
let png = rgba(&b64(&s.execute("document.export", &json!({"format": "png", "background": "white"})).unwrap()));
|
||||
png.get_pixel(10, 10).0
|
||||
};
|
||||
let accurate = centre(&mut s);
|
||||
let shown = vectorcraft_color::Color::cmyk(0.0, 0.0, 0.0, 1.0).to_rgba8(1.0);
|
||||
assert!(accurate.iter().zip(shown).all(|(a, b)| a.abs_diff(b) <= 1), "accurate: {accurate:?}");
|
||||
assert!(accurate[0] > 10, "accurate: dark grey, not RGB black");
|
||||
s.execute("prefs.set", &json!({"key": "blackOnScreen", "value": "rich"})).unwrap();
|
||||
assert_eq!(centre(&mut s), accurate, "blackOnScreen does not change exports");
|
||||
s.execute("prefs.set", &json!({"key": "blackOutput", "value": "rich"})).unwrap();
|
||||
assert_eq!(centre(&mut s), [0, 0, 0, 255], "rich: RGB black");
|
||||
s.execute("select.all", &json!({})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": {"c": 0.6, "m": 0.4, "y": 0.4, "k": 1}})).unwrap();
|
||||
let rich = centre(&mut s);
|
||||
s.execute("prefs.set", &json!({"key": "blackOutput", "value": "accurate"})).unwrap();
|
||||
assert_eq!(centre(&mut s), rich, "a rich black shows the same either way");
|
||||
}
|
||||
|
||||
/// Output All Blacks as Rich Black reaches a CMYK document composed from ink planes (one with a
|
||||
/// blending mode) as it does one drawn directly, and leaves CMYK-model exports alone: only RGB
|
||||
/// output changes.
|
||||
#[test]
|
||||
fn black_output_rich_covers_ink_plane_documents_and_leaves_cmyk_exports_alone() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 40, "height": 20, "colorMode": "cmyk"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": {"c": 0, "m": 0, "y": 0, "k": 1}})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 30, "y": 0, "width": 10, "height": 20})).unwrap();
|
||||
s.execute("transparency.set", &json!({"blendMode": "multiply"})).unwrap();
|
||||
let png =
|
||||
|s: &mut Session| rgba(&b64(&s.execute("document.export", &json!({"format": "png", "background": "white"})).unwrap())).get_pixel(10, 10).0;
|
||||
let cmyk = |s: &mut Session, format: &str| b64(&s.execute("document.export", &json!({"format": format, "colorModel": "cmyk"})).unwrap());
|
||||
let accurate = png(&mut s);
|
||||
assert!(accurate[0] > 10, "accurate: dark grey, {accurate:?}");
|
||||
let inks = [cmyk(&mut s, "tiff"), cmyk(&mut s, "jpg")];
|
||||
s.execute("prefs.set", &json!({"key": "blackOutput", "value": "rich"})).unwrap();
|
||||
assert_eq!(png(&mut s), [0, 0, 0, 255], "rich: RGB black through the ink planes too");
|
||||
assert!(inks == [cmyk(&mut s, "tiff"), cmyk(&mut s, "jpg")], "CMYK exports keep the document's inks");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn formats_list_the_raster_options() {
|
||||
let mut s = Session::new();
|
||||
|
|
|
|||
|
|
@ -128,7 +128,7 @@ fn print(s: &mut Session, p: &Value) -> Result<Value> {
|
|||
let flat = super::rasterfx::flatten_raster_effects(doc);
|
||||
let doc = flat.as_ref().unwrap_or(doc);
|
||||
// Print as Bitmap and the flattener preset (Advanced) render and flatten it first.
|
||||
let prepared = super::printadvanced::prepare(PRINT, doc, &set, &s.prefs.flattener_presets)?;
|
||||
let prepared = super::printadvanced::prepare(PRINT, doc, &set, &s.prefs.flattener_presets, s.prefs.black_output == "rich")?;
|
||||
let path = str_param(p, "path");
|
||||
if !postscript {
|
||||
let r = vectorcraft_pdf::print(prepared.as_ref().unwrap_or(doc), &PrintOptions { settings: set, ..Default::default() })
|
||||
|
|
|
|||
|
|
@ -30,7 +30,8 @@ pub(crate) fn flattener(cmd: &str, set: &PrintSettings, saved: &[FlattenerPreset
|
|||
|
||||
/// `doc` as Print as Bitmap and the flattener preset of `set` print it (from `saved` presets), or
|
||||
/// `None` when neither applies. Print as Bitmap is for composite output.
|
||||
pub(crate) fn prepare(cmd: &str, doc: &Document, set: &PrintSettings, saved: &[FlattenerPreset]) -> Result<Option<Document>> {
|
||||
/// `rich_black`: Appearance of Black › Printing / Exporting › Output All Blacks as Rich Black.
|
||||
pub(crate) fn prepare(cmd: &str, doc: &Document, set: &PrintSettings, saved: &[FlattenerPreset], rich_black: bool) -> Result<Option<Document>> {
|
||||
let composite = set.output.mode == OutputMode::Composite;
|
||||
let bitmap = set.advanced.print_as_bitmap && composite;
|
||||
let flattener = flattener(cmd, set, saved)?;
|
||||
|
|
@ -39,7 +40,7 @@ pub(crate) fn prepare(cmd: &str, doc: &Document, set: &PrintSettings, saved: &[F
|
|||
}
|
||||
let printed = vectorcraft_pdf::printed_document(doc, set);
|
||||
if bitmap {
|
||||
return bitmap_document(cmd, &printed, set).map(Some);
|
||||
return bitmap_document(cmd, &printed, set, rich_black).map(Some);
|
||||
}
|
||||
let Some(mut o) = flattener else { return Ok(None) };
|
||||
// Composite overprints that were discarded or simulated aren't preserved either.
|
||||
|
|
@ -63,13 +64,13 @@ fn drop_guides(nodes: &mut Vec<Arc<Node>>) {
|
|||
/// `doc` (as it prints) with its art replaced by one image of each printed region (an artboard
|
||||
/// with its bleed, or all the art), at the document's raster effects resolution; regions where
|
||||
/// nothing is drawn get none.
|
||||
fn bitmap_document(cmd: &str, doc: &Document, set: &PrintSettings) -> Result<Document> {
|
||||
fn bitmap_document(cmd: &str, doc: &Document, set: &PrintSettings, rich_black: bool) -> Result<Document> {
|
||||
let regions = vectorcraft_pdf::print_regions(doc, set).map_err(|e| pdf_error(cmd, e))?;
|
||||
let bleed = set.bleed.of(doc);
|
||||
let mut art = doc.clone();
|
||||
drop_guides(&mut art.layers);
|
||||
let anti_alias = if doc.raster_effects.anti_alias { AntiAlias::Art } else { AntiAlias::None };
|
||||
let opts = RenderOptions { skip_templates: true, anti_alias, ..Default::default() };
|
||||
let opts = RenderOptions { skip_templates: true, anti_alias, rich_black, ..Default::default() };
|
||||
let mut out = doc.clone();
|
||||
let mut renderer = vectorcraft_render::Renderer::new();
|
||||
let mut images = vec![];
|
||||
|
|
|
|||
|
|
@ -84,11 +84,11 @@ fn a_flattener_preset_flattens_transparency_before_printing() {
|
|||
any
|
||||
};
|
||||
assert!(transparent(doc(&s)));
|
||||
let none = super::cmd::printadvanced::prepare("file.print", doc(&s), &settings(json!({})), &saved).unwrap();
|
||||
let none = super::cmd::printadvanced::prepare("file.print", doc(&s), &settings(json!({})), &saved, false).unwrap();
|
||||
assert!(none.is_none(), "transparency prints live without a preset");
|
||||
for name in ["High Resolution", "low"] {
|
||||
let set = settings(json!({"advanced": {"flattenerPreset": name}}));
|
||||
let flat = super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved).unwrap().unwrap();
|
||||
let flat = super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved, false).unwrap().unwrap();
|
||||
assert!(!transparent(&flat), "{name}: flattened");
|
||||
}
|
||||
// A saved preset by name; an unknown one is refused by preview and print alike.
|
||||
|
|
@ -105,7 +105,7 @@ fn print_as_bitmap_prints_an_image_of_each_artboard() {
|
|||
s.execute("artboard.new", &json!({"x": 300, "y": 0, "width": 200, "height": 100})).unwrap();
|
||||
let saved = s.prefs.flattener_presets.clone();
|
||||
let set = settings(json!({"advanced": {"printAsBitmap": true}}));
|
||||
let bitmap = super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved).unwrap().unwrap();
|
||||
let bitmap = super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved, false).unwrap().unwrap();
|
||||
let mut kinds = vec![];
|
||||
bitmap.walk(|n| kinds.push(matches!(n.kind, NodeKind::Image(_))));
|
||||
assert_eq!(kinds.iter().filter(|k| **k).count(), 1, "one image: the empty artboard gets none");
|
||||
|
|
@ -127,5 +127,33 @@ fn print_as_bitmap_prints_an_image_of_each_artboard() {
|
|||
let pv = s.execute("print.preview", &seps).unwrap();
|
||||
assert!(pv["warnings"].as_array().unwrap().iter().any(|w| w.as_str().unwrap().contains("Print as Bitmap")));
|
||||
let set = settings(seps["settings"].clone());
|
||||
assert!(super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved).unwrap().is_none());
|
||||
assert!(super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved, false).unwrap().is_none());
|
||||
}
|
||||
|
||||
/// Appearance of Black › Printing / Exporting (#394): Print as Bitmap draws pure CMYK black as RGB
|
||||
/// black when `rich_black` is on.
|
||||
#[test]
|
||||
fn print_as_bitmap_honours_rich_black() {
|
||||
let mut s = Session::new();
|
||||
s.execute("file.new", &json!({"width": 20, "height": 20, "colorMode": "cmyk"})).unwrap();
|
||||
s.execute("paint.setStroke", &json!({"none": true})).unwrap();
|
||||
s.execute("paint.setFill", &json!({"color": {"c": 0, "m": 0, "y": 0, "k": 1}})).unwrap();
|
||||
s.execute("shape.rectangle", &json!({"x": 0, "y": 0, "width": 20, "height": 20})).unwrap();
|
||||
let set = settings(json!({"advanced": {"printAsBitmap": true}}));
|
||||
let saved = s.prefs.flattener_presets.clone();
|
||||
let centre = |prepared: &Document| {
|
||||
let mut key = None;
|
||||
prepared.walk(|n| {
|
||||
if let NodeKind::Image(im) = &n.kind {
|
||||
key = Some(im.key.clone());
|
||||
}
|
||||
});
|
||||
let bytes = &prepared.images[key.as_ref().expect("bitmap image")].bytes;
|
||||
let img = image::load_from_memory(bytes).unwrap().to_rgba8();
|
||||
img.get_pixel(img.width() / 2, img.height() / 2).0
|
||||
};
|
||||
let accurate = centre(&super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved, false).unwrap().unwrap());
|
||||
assert!(accurate[0] > 10, "accurate: dark grey, {accurate:?}");
|
||||
let rich = centre(&super::cmd::printadvanced::prepare("file.print", doc(&s), &set, &saved, true).unwrap().unwrap());
|
||||
assert_eq!(rich, [0, 0, 0, 255], "rich: RGB black");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -60,6 +60,9 @@ pub struct RasterExportOptions {
|
|||
pub tga: tga::TgaOptions,
|
||||
/// PSD colour model, layers and profile.
|
||||
pub psd: psd::PsdOptions,
|
||||
/// Appearance of Black › Printing / Exporting › Output All Blacks as Rich Black: pure CMYK
|
||||
/// black (K alone at 100%) becomes RGB black in RGB raster exports (document values unchanged).
|
||||
pub rich_black: bool,
|
||||
}
|
||||
|
||||
impl Default for RasterExportOptions {
|
||||
|
|
@ -76,6 +79,7 @@ impl Default for RasterExportOptions {
|
|||
bmp: bmp::BmpOptions::default(),
|
||||
tga: tga::TgaOptions::default(),
|
||||
psd: psd::PsdOptions::default(),
|
||||
rich_black: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -99,6 +103,7 @@ impl RasterExportOptions {
|
|||
precise: true,
|
||||
// Shapes meeting edge to edge leave no seam (#983).
|
||||
supersample: true,
|
||||
rich_black: self.rich_black,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
|
|
@ -1802,7 +1802,11 @@ default: View › Actual Size / `view.actualSize` is one document point per scre
|
|||
96 screen points, an inch at the system's reference density whatever the display scaling). `blackOnScreen`
|
||||
(Appearance of Black › On Screen, `accurate` by default) sets how the canvas shows pure CMYK black, black ink alone
|
||||
at 100%: `accurate` shows it through the CMYK profile, a dark grey, and `rich` shows it as RGB black. Rich blacks,
|
||||
black tints and images show the same either way, and exports are unchanged. `antiAliasedBitmaps` (off by default;
|
||||
black tints and images show the same either way, and exports are unchanged. `blackOutput` (Appearance of Black ›
|
||||
Printing / Exporting, `accurate` by default) does the same for RGB raster exports (`document.export`,
|
||||
`document.serialize`, `document.exportSelection`, `document.exportForScreens`, `document.exportForOffice`) and for
|
||||
Print as Bitmap: `rich` draws pure CMYK black as RGB black in the pixels; CMYK ink exports and the document's
|
||||
colours stay as they are. `antiAliasedBitmaps` (off by default;
|
||||
desktop app): in View › Pixel Preview, on softens placed and embedded bitmaps; off, their pixels stay hard-edged.
|
||||
`disableAutoAddDelete` (off by default): on, the Pen no longer adds or deletes an anchor when a click lands on a
|
||||
segment or an anchor of a selected path.
|
||||
|
|
|
|||
File diff suppressed because one or more lines are too long
Loading…
Reference in New Issue