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"
version = "0.11.0"
dependencies = [
"arrayvec",
"base64",
"bytemuck",
"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-assets = { git = "https://github.com/typst/typst-assets", rev = "4ee794c" }
typst-dev-assets = { git = "https://github.com/typst/typst-dev-assets", rev = "48a924d" }
arrayvec = "0.7.4"
az = "1.2"
base64 = "0.22"
bitflags = { version = "2", features = ["serde"] }

View File

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

View File

@ -1,3 +1,4 @@
use arrayvec::ArrayVec;
use once_cell::sync::Lazy;
use pdf_writer::{types::DeviceNSubtype, writers, Chunk, Dict, Filter, Name, Ref};
use typst::visualize::{Color, ColorSpace, Paint};
@ -377,26 +378,34 @@ impl PaintEncode for Color {
/// Extra color space functions.
pub(super) trait ColorSpaceExt {
/// Returns the range of the color space.
fn range(self) -> [f32; 6];
fn range(self) -> &'static [f32];
/// 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 {
fn range(self) -> [f32; 6] {
[0.0, 1.0, 0.0, 1.0, 0.0, 1.0]
fn range(self) -> &'static [f32] {
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] {
let range = self.range();
let [x, y, z, _] = self.encode(color);
fn convert<U: QuantizedColor>(self, color: Color) -> ArrayVec<U, 4> {
let components = self.encode(color);
[
U::quantize(x, [range[0], range[1]]),
U::quantize(y, [range[2], range[3]]),
U::quantize(z, [range[4], range[5]]),
]
self.range()
.chunks(2)
.zip(components)
.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_flag(8)
.shading_type(StreamShadingType::CoonsPatch)
.decode([
0.0, 1.0, 0.0, 1.0, range[0], range[1], range[2], range[3],
range[4], range[5],
])
.decode(
[0.0, 1.0, 0.0, 1.0].into_iter().chain(range.iter().copied()),
)
.anti_alias(gradient.anti_alias())
.filter(Filter::FlateDecode);
@ -216,7 +215,7 @@ fn shading_function(
chunk
.stitching_function(function)
.domain([0.0, 1.0])
.range(color_space.range())
.range(color_space.range().iter().copied())
.functions(functions)
.bounds(bounds)
.encode(encode);
@ -235,7 +234,7 @@ fn single_gradient(
let reference = chunk.alloc();
chunk
.exponential_function(reference)
.range(color_space.range())
.range(color_space.range().iter().copied())
.c0(color_space.convert(first_color))
.c1(color_space.convert(second_color))
.domain([0.0, 1.0])
@ -344,13 +343,13 @@ fn register_gradient(
/// Structure:
/// - flag: `u8`
/// - points: `[u16; 24]`
/// - colors: `[u16; 12]`
/// - colors: `[u16; 4*N]` (N = number of components)
fn write_patch(
target: &mut Vec<u8>,
t: f32,
t1: f32,
c0: [u16; 3],
c1: [u16; 3],
c0: &[u16],
c1: &[u16],
angle: Angle,
) {
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,
]));
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.
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) {
@ -452,8 +453,8 @@ fn compute_vertex_stream(gradient: &Gradient, aspect_ratio: Ratio) -> Arc<Vec<u8
&mut vertices,
t0.get() as f32,
t1.get() as f32,
encode_space.convert(c0),
encode_space.convert(c1),
&encode_space.convert(c0),
&encode_space.convert(c1),
angle,
);
continue;
@ -483,8 +484,8 @@ fn compute_vertex_stream(gradient: &Gradient, aspect_ratio: Ratio) -> Arc<Vec<u8
&mut vertices,
t_x as f32,
t_next as f32,
encode_space.convert(c),
encode_space.convert(c_next),
&encode_space.convert(c),
&encode_space.convert(c_next),
angle,
);