Adjust the number of color components written to the pdf according to the color space (#4568)

This commit is contained in:
Florent Michel 2024-07-22 16:05:22 +01:00 committed by GitHub
parent 1d74c8e8bf
commit c4dd6fa062
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 42 additions and 29 deletions

1
Cargo.lock generated
View File

@ -2774,6 +2774,7 @@ dependencies = [
name = "typst-pdf" name = "typst-pdf"
version = "0.11.0" version = "0.11.0"
dependencies = [ dependencies = [
"arrayvec",
"base64", "base64",
"bytemuck", "bytemuck",
"comemo", "comemo",

View File

@ -28,6 +28,7 @@ typst-timing = { path = "crates/typst-timing", version = "0.11.0" }
typst-utils = { path = "crates/typst-utils", version = "0.11.0" } typst-utils = { path = "crates/typst-utils", version = "0.11.0" }
typst-assets = { git = "https://github.com/typst/typst-assets", rev = "4ee794c" } typst-assets = { git = "https://github.com/typst/typst-assets", rev = "4ee794c" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "48a924d" } typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "48a924d" }
arrayvec = "0.7.4"
az = "1.2" az = "1.2"
base64 = "0.22" base64 = "0.22"
bitflags = { version = "2", features = ["serde"] } bitflags = { version = "2", features = ["serde"] }

View File

@ -26,6 +26,7 @@ indexmap = { workspace = true }
miniz_oxide = { workspace = true } miniz_oxide = { workspace = true }
once_cell = { workspace = true } once_cell = { workspace = true }
pdf-writer = { workspace = true } pdf-writer = { workspace = true }
arrayvec = { workspace = true }
subsetter = { workspace = true } subsetter = { workspace = true }
svg2pdf = { workspace = true } svg2pdf = { workspace = true }
ttf-parser = { workspace = true } ttf-parser = { workspace = true }

View File

@ -1,3 +1,4 @@
use arrayvec::ArrayVec;
use once_cell::sync::Lazy; use once_cell::sync::Lazy;
use pdf_writer::{types::DeviceNSubtype, writers, Chunk, Dict, Filter, Name, Ref}; use pdf_writer::{types::DeviceNSubtype, writers, Chunk, Dict, Filter, Name, Ref};
use typst::visualize::{Color, ColorSpace, Paint}; use typst::visualize::{Color, ColorSpace, Paint};
@ -377,26 +378,34 @@ impl PaintEncode for Color {
/// Extra color space functions. /// Extra color space functions.
pub(super) trait ColorSpaceExt { pub(super) trait ColorSpaceExt {
/// Returns the range of the color space. /// Returns the range of the color space.
fn range(self) -> [f32; 6]; fn range(self) -> &'static [f32];
/// Converts a color to the color space. /// Converts a color to the color space.
fn convert<U: QuantizedColor>(self, color: Color) -> [U; 3]; fn convert<U: QuantizedColor>(self, color: Color) -> ArrayVec<U, 4>;
} }
impl ColorSpaceExt for ColorSpace { impl ColorSpaceExt for ColorSpace {
fn range(self) -> [f32; 6] { fn range(self) -> &'static [f32] {
[0.0, 1.0, 0.0, 1.0, 0.0, 1.0] match self {
ColorSpace::D65Gray => &[0.0, 1.0],
ColorSpace::Oklab => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::Oklch => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::LinearRgb => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::Srgb => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::Cmyk => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::Hsl => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
ColorSpace::Hsv => &[0.0, 1.0, 0.0, 1.0, 0.0, 1.0],
}
} }
fn convert<U: QuantizedColor>(self, color: Color) -> [U; 3] { fn convert<U: QuantizedColor>(self, color: Color) -> ArrayVec<U, 4> {
let range = self.range(); let components = self.encode(color);
let [x, y, z, _] = self.encode(color);
[ self.range()
U::quantize(x, [range[0], range[1]]), .chunks(2)
U::quantize(y, [range[2], range[3]]), .zip(components)
U::quantize(z, [range[4], range[5]]), .map(|(range, component)| U::quantize(component, [range[0], range[1]]))
] .collect()
} }
} }

View File

@ -145,10 +145,9 @@ pub fn write_gradients(
.bits_per_component(16) .bits_per_component(16)
.bits_per_flag(8) .bits_per_flag(8)
.shading_type(StreamShadingType::CoonsPatch) .shading_type(StreamShadingType::CoonsPatch)
.decode([ .decode(
0.0, 1.0, 0.0, 1.0, range[0], range[1], range[2], range[3], [0.0, 1.0, 0.0, 1.0].into_iter().chain(range.iter().copied()),
range[4], range[5], )
])
.anti_alias(gradient.anti_alias()) .anti_alias(gradient.anti_alias())
.filter(Filter::FlateDecode); .filter(Filter::FlateDecode);
@ -216,7 +215,7 @@ fn shading_function(
chunk chunk
.stitching_function(function) .stitching_function(function)
.domain([0.0, 1.0]) .domain([0.0, 1.0])
.range(color_space.range()) .range(color_space.range().iter().copied())
.functions(functions) .functions(functions)
.bounds(bounds) .bounds(bounds)
.encode(encode); .encode(encode);
@ -235,7 +234,7 @@ fn single_gradient(
let reference = chunk.alloc(); let reference = chunk.alloc();
chunk chunk
.exponential_function(reference) .exponential_function(reference)
.range(color_space.range()) .range(color_space.range().iter().copied())
.c0(color_space.convert(first_color)) .c0(color_space.convert(first_color))
.c1(color_space.convert(second_color)) .c1(color_space.convert(second_color))
.domain([0.0, 1.0]) .domain([0.0, 1.0])
@ -344,13 +343,13 @@ fn register_gradient(
/// Structure: /// Structure:
/// - flag: `u8` /// - flag: `u8`
/// - points: `[u16; 24]` /// - points: `[u16; 24]`
/// - colors: `[u16; 12]` /// - colors: `[u16; 4*N]` (N = number of components)
fn write_patch( fn write_patch(
target: &mut Vec<u8>, target: &mut Vec<u8>,
t: f32, t: f32,
t1: f32, t1: f32,
c0: [u16; 3], c0: &[u16],
c1: [u16; 3], c1: &[u16],
angle: Angle, angle: Angle,
) { ) {
let theta = -TAU * t + angle.to_rad() as f32 + PI; let theta = -TAU * t + angle.to_rad() as f32 + PI;
@ -390,11 +389,13 @@ fn write_patch(
p1, p1, p2, p2, cp1, cp2, p3, p3, p1, p1, p1, p1, p1, p1, p2, p2, cp1, cp2, p3, p3, p1, p1, p1, p1,
])); ]));
let colors =
[c0.map(u16::to_be), c0.map(u16::to_be), c1.map(u16::to_be), c1.map(u16::to_be)];
// Push the colors. // Push the colors.
target.extend_from_slice(bytemuck::cast_slice(&colors)); let colors = [c0, c0, c1, c1]
.into_iter()
.flat_map(|c| c.iter().copied().map(u16::to_be_bytes))
.flatten();
target.extend(colors);
} }
fn control_point(c: Point, r: f32, angle_start: f32, angle_end: f32) -> (Point, Point) { fn control_point(c: Point, r: f32, angle_start: f32, angle_end: f32) -> (Point, Point) {
@ -452,8 +453,8 @@ fn compute_vertex_stream(gradient: &Gradient, aspect_ratio: Ratio) -> Arc<Vec<u8
&mut vertices, &mut vertices,
t0.get() as f32, t0.get() as f32,
t1.get() as f32, t1.get() as f32,
encode_space.convert(c0), &encode_space.convert(c0),
encode_space.convert(c1), &encode_space.convert(c1),
angle, angle,
); );
continue; continue;
@ -483,8 +484,8 @@ fn compute_vertex_stream(gradient: &Gradient, aspect_ratio: Ratio) -> Arc<Vec<u8
&mut vertices, &mut vertices,
t_x as f32, t_x as f32,
t_next as f32, t_next as f32,
encode_space.convert(c), &encode_space.convert(c),
encode_space.convert(c_next), &encode_space.convert(c_next),
angle, angle,
); );