mirror of
https://github.com/typst/typst
synced 2025-05-14 17:15:28 +08:00
Adjust the number of color components written to the pdf according to the color space (#4568)
This commit is contained in:
parent
1d74c8e8bf
commit
c4dd6fa062
1
Cargo.lock
generated
1
Cargo.lock
generated
@ -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",
|
||||||
|
@ -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"] }
|
||||||
|
@ -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 }
|
||||||
|
@ -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()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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,
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user