separations: use US spelling

This commit is contained in:
aiongg committed 2026-10-20 03:25:47 +00:00
1 parent 602c915272
commit 2c80b65e98
11 files changed
+66 -66

No files matched your search

+1 -1
View File
@@ -138,7 +138,7 @@ fn knockout_groups_replace_what_their_elements_cover() {
// A stencil mask must not erase the red beside it. Where the stencil paints (every sample 0)
// its blue is drawn; a stencil composites rather than knocking the red out, and its exact
// colour also depends on its fill opacity (pdfcraft #2975), so only "blue was drawn here" is
// color also depends on its fill opacity (pdfcraft #2975), so only "blue was drawn here" is
// pinned.
let stencil = render(ko, &format!("{red}0 0 1 rg q 150 0 0 120 100 50 cm /Msk Do Q"));
check(&stencil, 50, 40, [255, 128, 128], "red beside a stencil");
+16 -16
View File
@@ -86,12 +86,12 @@ fn inks(spots: &[&str]) -> Vec<Ink> {
Ink::PROCESS.into_iter().chain(spots.iter().map(|s| spot(s))).collect()
}
/// The process plates and Gold, overprint honoured.
/// The process plates and Gold, overprint honored.
fn separate(pdf: &[u8]) -> Plates {
plates(pdf, &inks(&["Gold"]), true, None)
}
/// A spot colour whose alternate is a yellowish CMYK.
/// A spot color whose alternate is a yellowish CMYK.
const GOLD: &str = "[/Separation /Gold /DeviceCMYK << /FunctionType 2 /Domain [0 1] /C0 [0 0 0 0] /C1 [0 0.3 1 0] /N 1 >>]";
fn gold_resource() -> String {
@@ -109,15 +109,15 @@ fn device_cmyk_puts_each_component_on_its_own_plate() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn a_spot_colour_paints_its_own_plate_and_knocks_out_the_process_plates() {
fn a_spot_color_paints_its_own_plate_and_knocks_out_the_process_plates() {
let s = separate(&page_pdf("0 0 0 1 k 0 0 40 40 re f /CS0 cs 0.5 scn 10 10 20 20 re f", &gold_resource(), &[]));
assert_eq!(s.at(20, 20), [0, 0, 0, 0, 50], "knocked out under the spot colour");
assert_eq!(s.at(20, 20), [0, 0, 0, 0, 50], "knocked out under the spot color");
assert_eq!(s.at(2, 2), [0, 0, 0, 100, 0]);
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn overprinting_keeps_the_plates_a_colour_does_not_specify() {
fn overprinting_keeps_the_plates_a_color_does_not_specify() {
let resources = format!("{} /ExtGState << /GS1 << /op true >> >>", gold_resource());
let pdf = page_pdf("0 0 0 1 k 0 0 40 40 re f /GS1 gs /CS0 cs 0.5 scn 10 10 20 20 re f", &resources, &[]);
assert_eq!(separate(&pdf).at(20, 20), [0, 0, 0, 100, 50], "overprinted");
@@ -147,7 +147,7 @@ fn nonzero_overprint_mode_leaves_zero_device_cmyk_components() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn gray_and_rgb_are_process_colour_and_never_take_the_nonzero_overprint_mode() {
fn gray_and_rgb_are_process_color_and_never_take_the_nonzero_overprint_mode() {
let process = inks(&[]);
let gray = page_pdf("1 0 0 0 k 0 0 40 40 re f /M1 gs 0.25 g 10 10 20 20 re f", "/ExtGState << /M1 << /OP true /OPM 1 >> >>", &[]);
assert_eq!(plates(&gray, &process, true, None).at(20, 20), [0, 0, 0, 75], "gray is black only, and knocks out cyan");
@@ -172,7 +172,7 @@ fn the_all_colorant_paints_every_plate_and_none_paints_nothing() {
let resources = format!("/ColorSpace << /CS0 {GOLD} /Reg [/Separation /All {gray}] /No [/Separation /None {gray}] >>");
let content = "/CS0 cs 0.2 scn 0 0 40 40 re f /Reg cs 1 scn 0 0 20 40 re f /No cs 1 scn 20 0 20 40 re f";
let s = separate(&page_pdf(content, &resources, &[]));
assert_eq!(s.at(10, 20), [100, 100, 100, 100, 100], "registration colour");
assert_eq!(s.at(10, 20), [100, 100, 100, 100, 100], "registration color");
assert_eq!(s.at(30, 20), [0, 0, 0, 0, 20], "None leaves every plate as it is");
}
@@ -194,7 +194,7 @@ fn images_are_separated_sample_by_sample() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn a_spot_colour_image_overprints_like_any_paint() {
fn a_spot_color_image_overprints_like_any_paint() {
let image = stream(&format!("/Type /XObject /Subtype /Image /Width 1 /Height 1 /BitsPerComponent 8 /ColorSpace {GOLD}"), &[128]);
let resources = "/XObject << /Im1 5 0 R >> /ExtGState << /GS1 << /op true >> >>";
let pdf = |gs: &str| page_pdf(&format!("0 0 0 1 k 0 0 40 40 re f {gs} q 20 0 0 20 10 10 cm /Im1 Do Q"), resources, std::slice::from_ref(&image));
@@ -204,7 +204,7 @@ fn a_spot_colour_image_overprints_like_any_paint() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn shadings_are_separated_through_their_colour_space() {
fn shadings_are_separated_through_their_color_space() {
let shading = format!(
"<< /ShadingType 2 /ColorSpace {GOLD} /Coords [0 0 40 0] /Function << /FunctionType 2 /Domain [0 1] /C0 [0] /C1 [1] /N 1 >> /Extend [true true] >>"
);
@@ -216,16 +216,16 @@ fn shadings_are_separated_through_their_colour_space() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn an_uncoloured_pattern_paints_the_film_of_the_colour_it_is_used_with() {
fn an_uncolored_pattern_paints_the_film_of_the_color_it_is_used_with() {
let cell = stream("/PatternType 1 /PaintType 2 /TilingType 1 /BBox [0 0 10 10] /XStep 10 /YStep 10 /Resources << >>", b"0 0 10 10 re f");
let resources = format!("/ColorSpace << /PCS [/Pattern {GOLD}] >> /Pattern << /P1 5 0 R >>");
let s = separate(&page_pdf("0 0 0 1 k 0 0 40 40 re f /PCS cs 0.5 /P1 scn 0 0 40 40 re f", &resources, &[cell]));
assert_eq!(s.at(20, 20), [0, 0, 0, 0, 50], "the pattern's spot colour, knocking out black");
assert_eq!(s.at(20, 20), [0, 0, 0, 0, 50], "the pattern's spot color, knocking out black");
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn soft_masks_keep_the_luminosity_of_their_own_colours() {
fn soft_masks_keep_the_luminosity_of_their_own_colors() {
// A mask drawn in blue lets about a tenth of the black through. Drawn as the black
// plate's film, blue (no black ink) would read as white and let all of it through.
let group = stream("/Type /XObject /Subtype /Form /BBox [0 0 40 40] /Group << /S /Transparency /CS /DeviceRGB >>", b"0 0 1 rg 0 0 40 40 re f");
@@ -263,12 +263,12 @@ fn the_ink_sink_reports_spot_inks_of_patterns_and_images_but_not_of_soft_masks()
let seen = seen.lock().unwrap();
let names: Vec<&str> = seen.iter().map(|(ink, _)| ink.name()).collect();
assert_eq!(names, ["Silver", "Gold"], "in the order first painted; a mask's ink doesn't print");
assert_eq!(seen[0].1, [128, 128, 128], "Silver at 100% is its alternate colour");
assert_eq!(seen[0].1, [128, 128, 128], "Silver at 100% is its alternate color");
}
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn malformed_colour_spaces_and_overprint_parameters_draw_what_they_can() {
fn malformed_color_spaces_and_overprint_parameters_draw_what_they_can() {
let resources = "/ColorSpace << /A [/DeviceN [] /DeviceGray 0] /B [/Separation] /C [/Indexed /DeviceCMYK 300 <00>] >> /ExtGState << /G << /OP 7 /OPM /X /op (y) >> >>";
let pdf = page_pdf("/G gs /A cs 1 scn 0 0 9 9 re f /B cs 1 scn /C cs 255 scn 0 0 40 40 re f", resources, &[]);
plates(&pdf, &inks(&["Gold"]), true, None);
@@ -343,7 +343,7 @@ fn device_gray_stays_on_the_black_plate_under_a_simulation() {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn cie_and_icc_colours_convert_through_the_profile_relative_to_their_white() {
fn cie_and_icc_colors_convert_through_the_profile_relative_to_their_white() {
let resources =
"/ColorSpace << /D50 [/Lab << /WhitePoint [0.9642 1 0.8249] >>] /D65 [/Lab << /WhitePoint [0.9505 1 1.089] >>] /Gray [/ICCBased 5 0 R] >>";
let content = "/D50 cs 50 20 -10 scn 0 0 10 40 re f /D65 cs 100 0 0 scn 10 0 10 40 re f /Gray cs 0.5 scn 20 0 10 40 re f";
@@ -426,7 +426,7 @@ impl CmykConversion for Fixed {
#[cfg_attr(not(target_arch = "wasm32"), test)]
#[cfg_attr(target_arch = "wasm32", wasm_bindgen_test::wasm_bindgen_test)]
fn a_callers_cmyk_conversion_separates_process_colour() {
fn a_callers_cmyk_conversion_separates_process_color() {
let profile = synthetic_icc::cmyk_profile(PRESS, true);
let xyz = Arc::default();
let simulation = CmykSimulation::with_conversion(&profile, Fixed(Arc::clone(&xyz)));
+1 -1
View File
@@ -17,7 +17,7 @@
#![allow(dead_code)]
/// Grid points per input of the BToA table: fine enough that colours a little off the neutral
/// Grid points per input of the BToA table: fine enough that colors a little off the neutral
/// axis interpolate between unclamped grid points.
const BTOA_GRID: usize = 17;
+3 -3
View File
@@ -11,7 +11,7 @@ Print separations for the Craft apps:
- `coverage`: ink coverage at a pixel and over a page, total area coverage (TAC) per pixel,
and the pixels and regions over a TAC limit.
- `composite`: an sRGB preview of chosen plates.
- `cms`: process colour conversion into a CMYK printing condition through craft-cms.
- `cms`: process color conversion into a CMYK printing condition through craft-cms.
## Plates from an exported PDF
@@ -44,9 +44,9 @@ Inks are found by a low-resolution pass that records each spot ink a paint uses,
first painted. Spot inks used only inside soft masks are left out. Each spot gets a Lab
alternate measured from its sRGB appearance at 100%, so out-of-sRGB spots are clipped.
### Process colour
### Process color
RGB, CIE-based and ICCBased colours become CMYK through, in order:
RGB, CIE-based and ICCBased colors become CMYK through, in order:
1. the CMYK profile of the page's or the document's output intent (a `GTS_PDFX` intent first),
when craft-cms can convert into it;
+4 -4
View File
@@ -1,11 +1,11 @@
//! Process colour conversion for plate mode through craft-cms.
//! Process color conversion for plate mode through craft-cms.
use std::sync::{Arc, OnceLock};
use craft_cms::{Builtin, ColorSpace, Intent, Profile, Transform, TransformOptions, builtin, cached, math};
use craft_pdf::interpret::color::{CmykConversion, CmykSimulation};
/// Converts process colour into a CMYK printing condition with craft-cms: relative
/// Converts process color into a CMYK printing condition with craft-cms: relative
/// colorimetric, without black point compensation, as the plate renderer expects (see
/// [`CmykConversion`]). CMYK shows as sRGB relative colorimetric with black point
/// compensation. Transforms are built on first use and shared through craft-cms's cache.
@@ -55,7 +55,7 @@ impl CmsConversion {
}
/// A plate-mode printing condition converting through this, for the profile bytes `icc`
/// this was made from. ICCBased CMYK colours embedding those same bytes separate as they
/// this was made from. ICCBased CMYK colors embedding those same bytes separate as they
/// are.
pub fn simulation(self, icc: &[u8]) -> CmykSimulation {
CmykSimulation::with_conversion(icc, self)
@@ -131,7 +131,7 @@ impl CmykConversion for CmsConversion {
}
}
/// CIE L\*a\*b\* (D50) of an sRGB colour, relative colorimetric; `None` if craft-cms can't
/// CIE L\*a\*b\* (D50) of an sRGB color, relative colorimetric; `None` if craft-cms can't
/// convert.
pub(crate) fn srgb8_to_lab(rgb: [u8; 3]) -> Option<[f32; 3]> {
static T: OnceLock<Option<Arc<Transform>>> = OnceLock::new();
+9 -9
View File
@@ -1,4 +1,4 @@
//! The ink model: which inks a job prints with, and colours as tints of those inks.
//! The ink model: which inks a job prints with, and colors as tints of those inks.
use std::borrow::Cow;
use std::collections::{BTreeMap, BTreeSet};
@@ -21,7 +21,7 @@ impl Process {
/// The four process inks, in plate order.
pub const ALL: [Process; 4] = [Process::Cyan, Process::Magenta, Process::Yellow, Process::Black];
/// The colorant name a `Separation` or `DeviceN` colour space gives this ink.
/// The colorant name a `Separation` or `DeviceN` color space gives this ink.
pub fn name(self) -> &'static str {
match self {
Self::Cyan => "Cyan",
@@ -36,13 +36,13 @@ impl Process {
Self::ALL.into_iter().find(|p| p.name() == name)
}
/// The ink's position in a CMYK colour.
/// The ink's position in a CMYK color.
pub fn index(self) -> usize {
self as usize
}
}
/// How a spot ink looks, for previews and for printing it as process colour.
/// How a spot ink looks, for previews and for printing it as process color.
#[derive(Clone, Copy, Debug, PartialEq)]
pub enum Alternate {
/// CMYK components, `0.0..=1.0`.
@@ -54,7 +54,7 @@ pub enum Alternate {
/// A spot ink.
#[derive(Clone, Debug, PartialEq)]
pub struct Spot {
/// The colorant name, as a `Separation` colour space would name it, without PDF name
/// The colorant name, as a `Separation` color space would name it, without PDF name
/// escapes (see [`normalize_name`]).
pub name: String,
/// The ink at 100%.
@@ -135,7 +135,7 @@ impl InkSet {
/// Adds `ink` and returns its id. An ink whose name is already in the set (compared after
/// [`normalize_name`]) is not added again, and its existing id is returned; a spot named
/// `Cyan` … `Black` is the process ink. A spot's name is stored normalised. `None` for the
/// `Cyan` … `Black` is the process ink. A spot's name is stored normalized. `None` for the
/// names `All` and `None`, which are not inks (§8.6.6.4), and when the set is full
/// (65 536 inks).
pub fn add(&mut self, ink: Ink) -> Option<InkId> {
@@ -338,14 +338,14 @@ impl InkSet {
}
}
/// A colour as ink tints.
/// A color as ink tints.
#[derive(Clone, Debug, PartialEq)]
pub enum InkColor {
/// Tints `0.0..=1.0` of the listed inks; other inks are unspecified (they keep what is
/// under the paint when it overprints, and are knocked out otherwise). One entry is a
/// `Separation` colour, several a `DeviceN` one.
/// `Separation` color, several a `DeviceN` one.
Tints(Vec<(InkId, f32)>),
/// The same tint on every plate: the registration colour (the `All` colorant).
/// The same tint on every plate: the registration color (the `All` colorant).
All(f32),
/// No ink on any plate (the `None` colorant).
None,
+7 -7
View File
@@ -5,7 +5,7 @@
//! that overprints without naming the ink leaves the film as it is (ISO 32000-2 §8.6.7).
//! Clipping, anti-aliasing, soft masks, transparency groups and blending stay the renderer's
//! own. `Separation` and `DeviceN` colorants paint their own plates, DeviceCMYK its four
//! components, DeviceGray black only, and other process colour converts to CMYK through the
//! components, DeviceGray black only, and other process color converts to CMYK through the
//! printing condition (see [`Conversion`]).
//!
//! Ported from PdfCraft #2770 by Guillem Hermida (`crates/render/src/separations.rs` at
@@ -50,7 +50,7 @@ const MAX_PROFILE_BYTES: usize = 16 << 20;
/// The longest output condition kept, in characters.
const MAX_CONDITION: usize = 160;
/// The printing condition process colour converts to when the page has no usable output
/// The printing condition process color converts to when the page has no usable output
/// intent.
#[derive(Clone, Debug, Default)]
pub enum Fallback {
@@ -59,7 +59,7 @@ pub enum Fallback {
Fogra39,
/// The caller's CMYK ICC profile.
Profile(Arc<[u8]>),
/// The ISO 32000-2 §10.4.2.4 device formulas, black generation and undercolour removal the
/// The ISO 32000-2 §10.4.2.4 device formulas, black generation and undercolor removal the
/// identity: neutral RGB goes to black alone, ICCBased CMYK separates as it is.
DeviceFormulas,
}
@@ -67,7 +67,7 @@ pub enum Fallback {
/// How [`plates`] separates.
#[derive(Clone, Debug)]
pub struct Options {
/// Honour `OP`, `op` and `OPM` as a separating device does. Without it every paint knocks
/// Honor `OP`, `op` and `OPM` as a separating device does. Without it every paint knocks
/// out what is under it.
pub overprint: bool,
/// The printing condition when the page has no output intent with a usable CMYK profile.
@@ -80,7 +80,7 @@ impl Default for Options {
}
}
/// How process colour that isn't CMYK already became CMYK.
/// How process color that isn't CMYK already became CMYK.
#[derive(Clone, Debug, PartialEq)]
pub enum Conversion {
/// Through the CMYK profile of the page's or document's output intent (ISO 32000-2
@@ -179,7 +179,7 @@ pub fn plates(pdf: &[u8], page: usize, dpi: f32, opts: &Options) -> Result<Plate
}
let alternate = Alternate::Lab(srgb8_to_lab(swatch).unwrap_or([0.0; 3]));
let spot = Ink::Spot(Spot { name: ink.name().to_string(), alternate, solidity: None });
// A name that normalises to one already listed (`A#2341` and `AA`) has no plate of its
// A name that normalizes to one already listed (`A#2341` and `AA`) has no plate of its
// own.
match inks.add(spot) {
Some(id) if id.index() == separated.len() => separated.push(ink),
@@ -207,7 +207,7 @@ fn render<'a>(
settings: &InterpreterSettings,
scale: f32,
) -> Result<raster::Raster, Error> {
// The plate's gray film must keep its tints: no colour replacement.
// The plate's gray film must keep its tints: no color replacement.
let options = raster::Options { scale: [scale, scale], background: [255; 4], color_replacement: None, ..Default::default() };
Ok(raster::render(page, cache, settings, &options)?)
}
+3 -3
View File
@@ -29,7 +29,7 @@ fn stream(dict: &str, data: &[u8]) -> Vec<u8> {
out
}
/// A spot colour whose alternate is a yellowish CMYK.
/// A spot color whose alternate is a yellowish CMYK.
const GOLD: &str = "[/Separation /Gold /DeviceCMYK << /FunctionType 2 /Domain [0 1] /C0 [0 0 0 0] /C1 [0 0.3 1 0] /N 1 >>]";
/// Black over the page, Gold at 50% in the middle square, overprinting when `gs` sets `op`.
@@ -101,7 +101,7 @@ fn near(got: [u8; 4], expected: [u8; 4]) -> bool {
}
#[test]
fn process_colour_converts_through_the_output_intent_else_the_fallback() {
fn process_color_converts_through_the_output_intent_else_the_fallback() {
let synthetic = builtin::COATED_CMYK_ICC;
let intent = "/OutputIntents [<< /Type /OutputIntent /S /GTS_PDFX /OutputConditionIdentifier (Synthetic press) /DestOutputProfile 5 0 R >>]";
let red = |catalog: &str| page_pdf("1 0 0 rg 0 0 40 40 re f", "", catalog, &[stream("/N 4", synthetic)]);
@@ -145,7 +145,7 @@ fn spot_inks_past_the_cap_are_listed_not_separated_and_bad_input_is_refused() {
}
#[test]
fn lab_colours_convert_through_the_profile_and_lab_white_is_paper() {
fn lab_colors_convert_through_the_profile_and_lab_white_is_paper() {
let resources = "/ColorSpace << /D50 [/Lab << /WhitePoint [0.9642 1 0.8249] >>] /D65 [/Lab << /WhitePoint [0.9505 1 1.089] >>] >>";
let pdf = page_pdf("/D50 cs 50 20 -10 scn 0 0 20 40 re f /D65 cs 100 0 0 scn 20 0 20 40 re f", resources, "", &[]);
let p = plates(&pdf, 0, 72.0, &Options::default()).unwrap();
+6 -6
View File
@@ -13,7 +13,7 @@ re-sync brings these PdfCraft changes:
| PdfCraft PR | Crate | Change |
|---|---|---|
| #1691 | hayro-interpret | Patch 28: images with few possible pixel values convert each value once (spot-colour images) |
| #1691 | hayro-interpret | Patch 28: images with few possible pixel values convert each value once (spot-color images) |
| #1903, #3316 | hayro-syntax | CCITT images that declare `/Rows 0`, or fewer `/Rows` than `/Height`, decode to their height |
| #1954 | hayro-syntax | ASCII85 decoding stops at the stream's decode limit (here the per-document limit) |
| #1982 | hayro-syntax | `Page::base_dimensions` keeps a one-point floor after `/UserUnit` |
@@ -26,19 +26,19 @@ re-sync brings these PdfCraft changes:
| #2035 | hayro-syntax | Flate back-references are copied in runs |
| #3356 | hayro | A tiling pattern drawn once shows its cell at full scale |
| #3378 | hayro-syntax | Patch 20: spaces or tabs between `stream` and its line break are accepted |
| #3363 | hayro-syntax | A JP2 image in a colour space the decoder refuses is drawn by its component count |
| #3363 | hayro-syntax | A JP2 image in a color space the decoder refuses is drawn by its component count |
| #3412 | hayro-interpret | Type 3 glyph bounding boxes are transformed to device space before shading bounds are intersected |
PdfCraft's vendored `vello_common` patch (clip-intersection performance) is not part of this
reader snapshot.
Changes ported from PdfCraft pull requests that were open when they were ported, under the
same MIT OR Apache-2.0 licence. Code comments keep the pull request's patch numbers, except
same MIT OR Apache-2.0 license. Code comments keep the pull request's patch numbers, except
where noted below.
| PdfCraft PR | Author | Source commit | Files | Change |
|---|---|---|---|---|
| [#2770](https://github.com/storytold/pdfcraft/pull/2770) | Guillem Hermida (guillehr2) | [6fcf2a4](https://github.com/guillehr2/pdfcraft/commit/6fcf2a4aca29e943e28cb69017ff8f87d00656c6) | hayro-interpret `color.rs`, `interpret/mod.rs`, `interpret/path.rs`, `interpret/state.rs`, `pattern.rs`, `shading.rs`, `soft_mask.rs`, `x_object.rs` | Patches 35 and 36, plate mode: `InterpreterSettings::plate` draws one ink's separation as a gray film (`color::Plate`, `ColorSpace::ink_use`/`ink_tint`); the graphics state reads `OP`, `op` and `OPM` and an overprinting paint that doesn't specify the plate's ink leaves the plate as it is (ISO 32000-2 §8.6.7); `InterpreterSettings::ink_sink` reports spot inks; `color::CmykSimulation` converts process colour to an output intent's CMYK. Only the vendored interpreter part is ported; PdfCraft's `separations.rs` and Output Preview UI are not |
| [#2770](https://github.com/storytold/pdfcraft/pull/2770) | Guillem Hermida (guillehr2) | [6fcf2a4](https://github.com/guillehr2/pdfcraft/commit/6fcf2a4aca29e943e28cb69017ff8f87d00656c6) | hayro-interpret `color.rs`, `interpret/mod.rs`, `interpret/path.rs`, `interpret/state.rs`, `pattern.rs`, `shading.rs`, `soft_mask.rs`, `x_object.rs` | Patches 35 and 36, plate mode: `InterpreterSettings::plate` draws one ink's separation as a gray film (`color::Plate`, `ColorSpace::ink_use`/`ink_tint`); the graphics state reads `OP`, `op` and `OPM` and an overprinting paint that doesn't specify the plate's ink leaves the plate as it is (ISO 32000-2 §8.6.7); `InterpreterSettings::ink_sink` reports spot inks; `color::CmykSimulation` converts process color to an output intent's CMYK. Only the vendored interpreter part is ported; PdfCraft's `separations.rs` and Output Preview UI are not |
| [#2974](https://github.com/storytold/pdfcraft/pull/2974) | mtlcl410 | [bae6981](https://github.com/mtlcl410/pdfcraft/commit/bae69819594a6385a027fec1f67e6b3c36c259b4) | hayro-interpret `device.rs`, `x_object.rs`; hayro `renderer.rs` | Knockout groups (`/K true`) knock out: while one is innermost, fills, strokes, glyph outlines and shadings are drawn with `Compose::Copy` (weighted by coverage); an unmasked image's rectangle (`Device::knockout_image`) and a nested group's shape (an erase pass between `Device::begin_knockout_erase` and `end_knockout_erase`) are cleared before their layer composites; a transparency group drawn in a knockout group always gets a layer of its own. Masked images and stencils composite as before |
Code comments label #2974's changes `Knockout patch (pdfcraft #2974)` instead of a number: the
@@ -49,9 +49,9 @@ object where two objects overlap. The erase pass resolves the group's resources
`Resources::from_scope`, as the group's own draw does in this tree.
The output-intent conversion of patch 36 goes through a `color::CmykConversion` trait, so
that callers can convert with their own colour management. `CmykSimulation::new` keeps
that callers can convert with their own color management. `CmykSimulation::new` keeps
#2770's moxcms conversion as the default, and `CmykSimulation::with_conversion` takes a
caller's. Lab and ICCBased colours reach the conversion as CIE XYZ relative to the D50 PCS
caller's. Lab and ICCBased colors reach the conversion as CIE XYZ relative to the D50 PCS
white (`color::PCS_WHITE`); the moxcms conversion takes them on through #2770's ProPhoto hub.
`crates/pdf/tests/plates.rs` adapts #2770's plate tests to the raster path, with its
synthetic ICC profiles in `crates/pdf/tests/support/synthetic_icc.rs`.
+1 -1
View File
@@ -182,7 +182,7 @@
"path": "src/color.rs",
"source_sha256": "799ce29bb5e59c8fc94db202873e48c2047dd35962e6f26efd215156c47158c1",
"source_git_blob": "56bb04f24c04ba33ab6bf99c02a24735670959ad",
"sha256": "ed70bdb9618cf4d65032e977efe60b4d36f868fa4040db1012bfaf9ab4f5fb6e"
"sha256": "50a039fbf0d8122b31fe03c0a06e2d4bb2994f50fd04072f6637233bc2ff9eb6"
},
{
"path": "src/context.rs",
+15 -15
View File
@@ -785,7 +785,7 @@ impl Lab {
]
}
/// PdfCraft patch (36): the colour `input` as XYZ relative to [`PCS_WHITE`], relative
/// PdfCraft patch (36): the color `input` as XYZ relative to [`PCS_WHITE`], relative
/// colorimetric: the space's white point becomes the PCS white (Bradford-adapted).
fn to_pcs(&self, input: &[f32], manual_scale: bool) -> [f32; 3] {
let xyz = self.xyz(self.components(input, manual_scale));
@@ -1091,8 +1091,8 @@ impl ICCProfile {
})))
}
/// PdfCraft patch (36): `input` (whole colours of this profile's components) as XYZ
/// relative to [`PCS_WHITE`], three values per colour in `xyz`, through the separation hub
/// PdfCraft patch (36): `input` (whole colors of this profile's components) as XYZ
/// relative to [`PCS_WHITE`], three values per color in `xyz`, through the separation hub
/// (see [`Hub`]). L*a*b* components are scaled to the profile's encoding unless
/// `manual_scale` says they already are (an Indexed palette's).
fn to_pcs(&self, input: &[f32], manual_scale: bool, xyz: &mut [f32]) -> Option<()> {
@@ -1125,9 +1125,9 @@ impl ICCProfile {
};
}
transform.transform(encoded, xyz).ok()?;
for colour in xyz.chunks_exact_mut(3) {
let pcs = HUB.to_pcs(&[colour[0], colour[1], colour[2]]);
colour.copy_from_slice(&pcs);
for color in xyz.chunks_exact_mut(3) {
let pcs = HUB.to_pcs(&[color[0], color[1], color[2]]);
color.copy_from_slice(&pcs);
}
Some(())
}
@@ -1456,15 +1456,15 @@ struct SimulationRepr {
}
/// The conversion into a [`CmykSimulation`]'s CMYK, relative colorimetric. Each call converts
/// whole colours, at most 256 of them; CMYK components are `0.0..=1.0`, four per colour. A
/// method returns `None` when it can't convert, and the colour then separates by the device
/// whole colors, at most 256 of them; CMYK components are `0.0..=1.0`, four per color. A
/// method returns `None` when it can't convert, and the color then separates by the device
/// formulas.
pub trait CmykConversion: Send + Sync {
/// sRGB colours, gamma-encoded, three components in `0.0..=1.0` per colour, to CMYK.
/// sRGB colors, gamma-encoded, three components in `0.0..=1.0` per color, to CMYK.
fn from_srgb(&self, rgb: &[f32], cmyk: &mut [f32]) -> Option<()>;
/// CIE XYZ colours relative to [`PCS_WHITE`] (the Y of white is 1), three components per
/// colour, to CMYK. The source's white has already been adapted to the PCS white.
/// CIE XYZ colors relative to [`PCS_WHITE`] (the Y of white is 1), three components per
/// color, to CMYK. The source's white has already been adapted to the PCS white.
fn from_pcs_xyz(&self, xyz: &[f32], cmyk: &mut [f32]) -> Option<()>;
/// CMYK bytes, four per pixel, to sRGB bytes, three per pixel, to show what the printing
@@ -1487,7 +1487,7 @@ pub trait CmykConversion: Send + Sync {
}
/// The D50 white of the ICC profile connection space (ICC.1 §7.2.16), the white that
/// [`CmykConversion::from_pcs_xyz`] takes its colours relative to.
/// [`CmykConversion::from_pcs_xyz`] takes its colors relative to.
pub const PCS_WHITE: [f32; 3] = [0.9642, 1.0, 0.8249];
impl Debug for CmykSimulation {
@@ -1530,7 +1530,7 @@ impl CmykSimulation {
}
/// The printing condition of the CMYK ICC profile `profile`, converted to by `conversion`,
/// which the caller made from that profile. ICCBased CMYK colours in `profile` itself stay
/// which the caller made from that profile. ICCBased CMYK colors in `profile` itself stay
/// as they are.
pub fn with_conversion(profile: &[u8], conversion: impl CmykConversion + 'static) -> Self {
Self(Arc::new(SimulationRepr {
@@ -1569,7 +1569,7 @@ impl CmykSimulation {
}
}
/// PdfCraft patch (36): the conversion [`CmykSimulation::new`] makes with moxcms. XYZ colours
/// PdfCraft patch (36): the conversion [`CmykSimulation::new`] makes with moxcms. XYZ colors
/// pass through the separation hub (see [`Hub`]).
struct MoxcmsConversion {
description: Option<String>,
@@ -1708,7 +1708,7 @@ fn transform_u8(
static SRGB: LazyLock<ColorProfile> = LazyLock::new(ColorProfile::new_srgb);
/// PdfCraft patch (36): the separation hub, the RGB that ICCBased colours leave their profile
/// PdfCraft patch (36): the separation hub, the RGB that ICCBased colors leave their profile
/// in, and that [`MoxcmsConversion`] takes PCS XYZ to its CMYK through: ROMM RGB (ProPhoto)
/// primaries, D50 white, gamma 1.8. Its
/// gamut holds practically every surface colour, so nothing printable clips on the way, and