mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-24 10:27:00 -06:00
Fixes #426 Co-Authored-By: Claude Haiku 5.5 <noreply@anthropic.com> Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
61 lines
2.4 KiB
Rust
61 lines
2.4 KiB
Rust
//! CMYK export converts the colours inside vector pattern tiles (#426).
|
|
|
|
#![allow(clippy::unwrap_used, clippy::expect_used, clippy::panic)]
|
|
|
|
use figcraft_color::{Color, Paint};
|
|
use figcraft_doc::{Document, NodeKind, PrintSettings};
|
|
use figcraft_pdf::{PdfOptions, export_pdf};
|
|
use std::io::Read;
|
|
|
|
/// Every zlib stream of `pdf`, inflated and joined.
|
|
fn streams(pdf: &[u8]) -> String {
|
|
let mut out = String::new();
|
|
let mut rest = pdf;
|
|
while let Some(i) = rest.windows(7).position(|w| w == b"stream\n") {
|
|
rest = &rest[i + 7..];
|
|
let end = rest.windows(9).position(|w| w == b"endstream").unwrap();
|
|
let mut bytes = Vec::new();
|
|
if flate2::read::ZlibDecoder::new(&rest[..end]).read_to_end(&mut bytes).is_ok() {
|
|
out.push_str(&String::from_utf8_lossy(&bytes));
|
|
out.push('\n');
|
|
}
|
|
rest = &rest[end + 9..];
|
|
}
|
|
out
|
|
}
|
|
|
|
fn export(pattern: bool, cmyk: bool) -> (String, String) {
|
|
let mut doc = Document::new("fixture");
|
|
let page = doc.first_page().unwrap();
|
|
let source = doc.create(page, NodeKind::Rectangle, "Source", 40.0, 0.0, 10.0, 10.0).unwrap();
|
|
let green = Paint::solid(Color::from_hex("00FF00").unwrap());
|
|
doc.get_mut(source).unwrap().fills = vec![green.clone()];
|
|
let target = doc.create(page, NodeKind::Rectangle, "Target", 0.0, 0.0, 20.0, 20.0).unwrap();
|
|
doc.get_mut(target).unwrap().fills = vec![if pattern { Paint::pattern(source.0) } else { green }];
|
|
let opts = PdfOptions { print: PrintSettings { cmyk, ..Default::default() }, ..Default::default() };
|
|
let pdf = export_pdf(&doc, &[target], &opts).unwrap();
|
|
(String::from_utf8_lossy(&pdf).into_owned(), streams(&pdf))
|
|
}
|
|
|
|
fn has_rgb_op(content: &str) -> bool {
|
|
content.split_whitespace().any(|op| op == "rg" || op == "RG")
|
|
}
|
|
|
|
#[test]
|
|
fn pattern_cmyk_controls() {
|
|
let (_, solid) = export(false, true);
|
|
assert!(solid.contains("1 0 1 0 k"), "{solid}");
|
|
assert!(!has_rgb_op(&solid), "{solid}");
|
|
let (pdf, pattern) = export(true, false);
|
|
assert!(pdf.contains("/PatternType 1"));
|
|
assert!(pattern.contains("0 1 0 rg"), "{pattern}");
|
|
}
|
|
|
|
#[test]
|
|
fn pattern_colors_follow_cmyk_setting() {
|
|
let (pdf, content) = export(true, true);
|
|
assert!(pdf.contains("/PatternType 1"));
|
|
assert!(!has_rgb_op(&content), "RGB operator remains in CMYK pattern: {content}");
|
|
assert!(content.contains("1 0 1 0 k"), "green must convert to CMYK: {content}");
|
|
}
|