mirror of
https://github.com/storytold/craft-libs.git
synced 2026-11-05 18:20:09 +00:00
prepress: decode spot names from the PDF once, so A#41 and AA get their own plates
This commit is contained in:
1 parent
07f1250d6c
commit
f7b71a80a1
3 files changed
+43
-10
No files matched your search
@@ -147,22 +147,31 @@ impl InkSet {
|
||||
Ink::Spot(spot) => spot,
|
||||
};
|
||||
let name = normalize_name(&spot.name).into_owned();
|
||||
if name == "All" || name == "None" {
|
||||
self.add_decoded(Spot { name, ..spot })
|
||||
}
|
||||
|
||||
/// [`add`](Self::add) for a spot whose name is already decoded, as a PDF reader hands it
|
||||
/// over: `#` in the name is a literal character.
|
||||
pub(crate) fn add_decoded(&mut self, spot: Spot) -> Option<InkId> {
|
||||
if spot.name == "All" || spot.name == "None" {
|
||||
return None;
|
||||
}
|
||||
if let Some(id) = self.lookup(&name) {
|
||||
if let Some(id) = self.lookup_decoded(&spot.name) {
|
||||
return Some(id);
|
||||
}
|
||||
let id = InkId(u16::try_from(self.inks.len()).ok()?);
|
||||
self.inks.push(Ink::Spot(Spot { name, ..spot }));
|
||||
self.inks.push(Ink::Spot(spot));
|
||||
Some(id)
|
||||
}
|
||||
|
||||
/// The ink named `name`, compared after [`normalize_name`]: `"/Gold#20Foil"` finds
|
||||
/// `Gold Foil`.
|
||||
pub fn lookup(&self, name: &str) -> Option<InkId> {
|
||||
let name = normalize_name(name);
|
||||
if let Some(p) = Process::from_name(&name) {
|
||||
self.lookup_decoded(&normalize_name(name))
|
||||
}
|
||||
|
||||
fn lookup_decoded(&self, name: &str) -> Option<InkId> {
|
||||
if let Some(p) = Process::from_name(name) {
|
||||
return Some(InkId::process(p));
|
||||
}
|
||||
let at = self.inks.iter().skip(4).position(|ink| ink.name() == name)?;
|
||||
|
||||
@@ -24,7 +24,7 @@ use craft_pdf::syntax::object::{Array, Dict, Name, Stream, String as PdfText};
|
||||
use craft_pdf::{OpenError, open_slice};
|
||||
|
||||
use crate::cms::{CmsConversion, ProfileError, srgb8_to_lab};
|
||||
use crate::ink::{Alternate, Ink, InkId, InkSet, Spot};
|
||||
use crate::ink::{Alternate, InkId, InkSet, Spot};
|
||||
|
||||
/// Spot inks separated per page, after the four process inks. More than any press runs: a
|
||||
/// `DeviceN` space has at most 32 colorants, and every plate costs a render and a byte per
|
||||
@@ -178,10 +178,10 @@ pub fn plates(pdf: &[u8], page: usize, dpi: f32, opts: &Options) -> Result<Plate
|
||||
continue;
|
||||
}
|
||||
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 normalizes to one already listed (`A#2341` and `AA`) has no plate of its
|
||||
// own.
|
||||
match inks.add(spot) {
|
||||
let spot = Spot { name: ink.name().to_string(), alternate, solidity: None };
|
||||
// hayro hands over names with their `#xx` escapes decoded, so `#` here is a literal
|
||||
// character. Two names that read the same after lossy UTF-8 decoding share one plate.
|
||||
match inks.add_decoded(spot) {
|
||||
Some(id) if id.index() == separated.len() => separated.push(ink),
|
||||
_ => unseparated.push(ink.name().to_string()),
|
||||
}
|
||||
|
||||
@@ -144,6 +144,30 @@ fn spot_inks_past_the_cap_are_listed_not_separated_and_bad_input_is_refused() {
|
||||
assert!(matches!(plates(b"not a pdf", 0, 72.0, &Options::default()), Err(Error::Open(_))));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn escaped_spot_names_are_decoded_once_and_each_gets_its_own_plate() {
|
||||
// `/A#2341` is the spot `A#41`, not `AA`; `/Spot#20#2312` is `Spot #12`.
|
||||
let names = ["/A#2341", "/AA", "/Spot#20#2312"];
|
||||
let spaces: String = names
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, name)| format!("/S{i} [/Separation {name} /DeviceGray << /FunctionType 2 /Domain [0 1] /C0 [1] /C1 [0] /N 1 >>] "))
|
||||
.collect();
|
||||
let content: String = (0..names.len()).map(|i| format!("/S{i} cs 1 scn {} 0 10 10 re f ", i * 10)).collect();
|
||||
let pdf = page_pdf(&content, &format!("/ColorSpace << {spaces} >>"), "", &[]);
|
||||
let p = plates(&pdf, 0, 72.0, &Options::default()).unwrap();
|
||||
let spots: Vec<&str> = p.inks.spots().map(|(_, s)| s.name.as_str()).collect();
|
||||
assert_eq!(spots, ["A#41", "AA", "Spot #12"]);
|
||||
assert!(p.unseparated.is_empty());
|
||||
assert_eq!(p.planes.len(), 7);
|
||||
for (i, (id, _)) in p.inks.spots().enumerate() {
|
||||
for x in [5u32, 15, 25] {
|
||||
let expected = if (x / 10) as usize == i { 255 } else { 0 };
|
||||
assert_eq!(p.tint(id, x, 35), Some(expected), "spot {i} at x = {x}");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
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] >>] >>";
|
||||
|
||||
Reference in new issue
Block a user