1#![allow(clippy::needless_range_loop)]
4
5use crate::CacheKey;
6use crate::WarningSinkFn;
7use crate::cache::Cache;
8use crate::color::{ColorComponents, ColorSpace};
9use crate::function::{Function, Values, interpolate};
10use crate::util::decode_or_warn;
11use crate::util::{Float32Ext, PointExt, RectExt};
12use kurbo::{Affine, BezPath, CubicBez, ParamCurve, Point, Shape};
13use log::warn;
14use pdf_syntax::bit_reader::BitReader;
15use pdf_syntax::object::Array;
16use pdf_syntax::object::Dict;
17use pdf_syntax::object::Object;
18use pdf_syntax::object::Rect;
19use pdf_syntax::object::Stream;
20use pdf_syntax::object::dict::keys::{
21 BACKGROUND, BBOX, BITS_PER_COMPONENT, BITS_PER_COORDINATE, BITS_PER_FLAG, COLORSPACE, COORDS,
22 DECODE, DOMAIN, EXTEND, FUNCTION, MATRIX, SHADING_TYPE, VERTICES_PER_ROW,
23};
24use smallvec::{SmallVec, smallvec};
25use std::sync::Arc;
26
27#[derive(Debug, Clone)]
29pub enum ShadingFunction {
30 Single(Function),
32 Multiple(SmallVec<[Function; 4]>),
34}
35
36impl ShadingFunction {
37 pub fn eval(&self, input: &Values) -> Option<Values> {
39 match self {
40 Self::Single(s) => s.eval(input.clone()),
41 Self::Multiple(m) => {
42 let mut out = smallvec![];
45
46 for func in m {
47 out.push(*func.eval(input.clone())?.first()?);
48 }
49
50 Some(out)
51 }
52 }
53 }
54}
55
56#[derive(Debug)]
58pub enum ShadingType {
59 FunctionBased {
61 domain: [f32; 4],
63 matrix: Affine,
65 function: ShadingFunction,
67 },
68 RadialAxial {
70 coords: [f32; 6],
78 domain: [f32; 2],
80 function: ShadingFunction,
82 extend: [bool; 2],
84 axial: bool,
86 },
87 TriangleMesh {
89 triangles: Vec<Triangle>,
91 function: Option<ShadingFunction>,
93 },
94 CoonsPatchMesh {
96 patches: Vec<CoonsPatch>,
98 function: Option<ShadingFunction>,
100 },
101 TensorProductPatchMesh {
103 patches: Vec<TensorProductPatch>,
105 function: Option<ShadingFunction>,
107 },
108 Dummy,
110}
111
112#[derive(Clone, Debug)]
114pub struct Shading {
115 cache_key: u128,
116 pub shading_type: Arc<ShadingType>,
118 pub color_space: ColorSpace,
120 pub clip_path: Option<BezPath>,
122 pub background: Option<SmallVec<[f32; 4]>>,
124}
125
126impl Shading {
127 pub(crate) fn new(
128 dict: &Dict<'_>,
129 stream: Option<&Stream<'_>>,
130 cache: &Cache,
131 warning_sink: &WarningSinkFn,
132 ) -> Option<Self> {
133 let cache_key = dict.cache_key();
134
135 let shading_num = dict.get::<u8>(SHADING_TYPE)?;
136
137 let color_space = ColorSpace::new(dict.get(COLORSPACE)?, cache, warning_sink)?;
138
139 let shading_type = match shading_num {
140 1 => {
141 let domain = dict.get::<[f32; 4]>(DOMAIN).unwrap_or([0.0, 1.0, 0.0, 1.0]);
142 let matrix = dict
143 .get::<[f64; 6]>(MATRIX)
144 .map(Affine::new)
145 .unwrap_or_default();
146 let function = read_function(dict, &color_space, warning_sink)?;
147
148 ShadingType::FunctionBased {
149 domain,
150 matrix,
151 function,
152 }
153 }
154 2 | 3 => {
155 let domain = dict.get::<[f32; 2]>(DOMAIN).unwrap_or([0.0, 1.0]);
156 let function = read_function(dict, &color_space, warning_sink)?;
157 let extend = dict.get::<[bool; 2]>(EXTEND).unwrap_or([false, false]);
158 let (coords, invalid) = if shading_num == 2 {
159 let read = dict.get::<[f32; 4]>(COORDS)?;
160 let invalid = (read[0] - read[2]).is_nearly_zero()
161 && (read[1] - read[3]).is_nearly_zero();
162 ([read[0], read[1], read[2], read[3], 0.0, 0.0], invalid)
163 } else {
164 let read = dict.get::<[f32; 6]>(COORDS)?;
165 let invalid = (read[0] - read[3]).is_nearly_zero()
166 && (read[1] - read[4]).is_nearly_zero()
167 && (read[2] - read[5]).is_nearly_zero();
168 (read, invalid)
169 };
170
171 let axial = shading_num == 2;
172
173 if invalid {
174 ShadingType::Dummy
175 } else {
176 ShadingType::RadialAxial {
177 domain,
178 function,
179 extend,
180 coords,
181 axial,
182 }
183 }
184 }
185 4 => {
186 let stream = stream?;
187 let stream_data = decode_or_warn(stream, warning_sink)?;
188 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
189 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
190 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
191 let function = read_function(dict, &color_space, warning_sink);
192 let decode = dict
193 .get::<Array<'_>>(DECODE)?
194 .iter::<f32>()
195 .collect::<Vec<_>>();
196
197 let triangles = read_free_form_triangles(
198 stream_data.as_ref(),
199 bpf,
200 bp_coord,
201 bp_comp,
202 function.is_some(),
203 &decode,
204 )?;
205
206 ShadingType::TriangleMesh {
207 triangles,
208 function,
209 }
210 }
211 5 => {
212 let stream = stream?;
213 let stream_data = decode_or_warn(stream, warning_sink)?;
214 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
215 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
216 let function = read_function(dict, &color_space, warning_sink);
217 let decode = dict
218 .get::<Array<'_>>(DECODE)?
219 .iter::<f32>()
220 .collect::<Vec<_>>();
221 let vertices_per_row = dict.get::<u32>(VERTICES_PER_ROW)?;
222
223 let triangles = read_lattice_triangles(
224 stream_data.as_ref(),
225 bp_coord,
226 bp_comp,
227 function.is_some(),
228 vertices_per_row,
229 &decode,
230 )?;
231
232 ShadingType::TriangleMesh {
233 triangles,
234 function,
235 }
236 }
237 6 => {
238 let stream = stream?;
239 let stream_data = decode_or_warn(stream, warning_sink)?;
240 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
241 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
242 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
243 let function = read_function(dict, &color_space, warning_sink);
244 let decode = dict
245 .get::<Array<'_>>(DECODE)?
246 .iter::<f32>()
247 .collect::<Vec<_>>();
248
249 let patches = read_coons_patch_mesh(
250 stream_data.as_ref(),
251 bpf,
252 bp_coord,
253 bp_comp,
254 function.is_some(),
255 &decode,
256 )?;
257
258 ShadingType::CoonsPatchMesh { patches, function }
259 }
260 7 => {
261 let stream = stream?;
262 let stream_data = decode_or_warn(stream, warning_sink)?;
263 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
264 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
265 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
266 let function = read_function(dict, &color_space, warning_sink);
267 let decode = dict
268 .get::<Array<'_>>(DECODE)?
269 .iter::<f32>()
270 .collect::<Vec<_>>();
271
272 let patches = read_tensor_product_patch_mesh(
273 stream_data.as_ref(),
274 bpf,
275 bp_coord,
276 bp_comp,
277 function.is_some(),
278 &decode,
279 )?;
280
281 ShadingType::TensorProductPatchMesh { patches, function }
282 }
283 _ => return None,
284 };
285
286 let bbox = dict.get::<Rect>(BBOX).map(|r| r.to_kurbo());
287 let background = dict
288 .get::<Array<'_>>(BACKGROUND)
289 .map(|a| a.iter::<f32>().collect::<SmallVec<_>>());
290
291 Some(Self {
292 cache_key,
293 shading_type: Arc::new(shading_type),
294 color_space,
295 clip_path: bbox.map(|r| r.to_path(0.1)),
296 background,
297 })
298 }
299}
300
301impl CacheKey for Shading {
302 fn cache_key(&self) -> u128 {
303 self.cache_key
304 }
305}
306
307#[derive(Clone, Debug)]
309pub struct Triangle {
310 pub p0: TriangleVertex,
312 pub p1: TriangleVertex,
314 pub p2: TriangleVertex,
316 kurbo_tri: kurbo::Triangle,
317 d00: f64,
318 d01: f64,
319 d11: f64,
320}
321
322impl Triangle {
323 pub fn new(p0: TriangleVertex, p1: TriangleVertex, p2: TriangleVertex) -> Self {
325 let v0 = p1.point - p0.point;
326 let v1 = p2.point - p0.point;
327
328 let d00 = v0.dot(v0);
329 let d01 = v0.dot(v1);
330 let d11 = v1.dot(v1);
331
332 let kurbo_tri = kurbo::Triangle::new(p0.point, p1.point, p2.point);
333
334 Self {
335 p0,
336 p1,
337 kurbo_tri,
338 p2,
339 d00,
340 d01,
341 d11,
342 }
343 }
344
345 pub fn interpolate(&self, pos: Point) -> ColorComponents {
349 let (u, v, w) = self.barycentric_coords(pos);
350
351 let mut result = smallvec![];
352
353 for i in 0..self.p0.colors.len() {
354 let c0 = self.p0.colors[i];
355 let c1 = self.p1.colors[i];
356 let c2 = self.p2.colors[i];
357 result.push(u * c0 + v * c1 + w * c2);
358 }
359
360 result
361 }
362
363 pub fn contains_point(&self, pos: Point) -> bool {
365 self.kurbo_tri.winding(pos) != 0
366 }
367
368 pub fn bounding_box(&self) -> kurbo::Rect {
370 self.kurbo_tri.bounding_box()
371 }
372
373 fn barycentric_coords(&self, p: Point) -> (f32, f32, f32) {
374 let (a, b, c) = (self.p0.point, self.p1.point, self.p2.point);
375 let v0 = b - a;
376 let v1 = c - a;
377 let v2 = p - a;
378
379 let d00 = self.d00;
380 let d01 = self.d01;
381 let d11 = self.d11;
382 let d20 = v2.dot(v0);
383 let d21 = v2.dot(v1);
384
385 let denom = d00 * d11 - d01 * d01;
386 let v = (d11 * d20 - d01 * d21) / denom;
387 let w = (d00 * d21 - d01 * d20) / denom;
388 let u = (1.0 - v - w) as f32;
389
390 (u, v as f32, w as f32)
391 }
392}
393
394#[derive(Clone, Debug)]
396pub struct TriangleVertex {
397 flag: u32,
398 pub point: Point,
400 pub colors: ColorComponents,
402}
403
404impl TriangleVertex {
405 #[allow(dead_code)]
409 pub(crate) fn new(flag: u32, point: Point, colors: ColorComponents) -> Self {
410 Self {
411 flag,
412 point,
413 colors,
414 }
415 }
416}
417
418#[derive(Clone, Debug)]
420pub struct CoonsPatch {
421 pub control_points: [Point; 12],
423 pub colors: [ColorComponents; 4],
425}
426
427#[derive(Clone, Debug)]
429pub struct TensorProductPatch {
430 pub control_points: [Point; 16],
432 pub colors: [ColorComponents; 4],
434}
435
436impl CoonsPatch {
437 pub fn map_coordinate(&self, p: Point) -> Point {
439 let (u, v) = (p.x, p.y);
440
441 let cp = &self.control_points;
442
443 let c1 = CubicBez::new(cp[0], cp[11], cp[10], cp[9]);
444 let c2 = CubicBez::new(cp[3], cp[4], cp[5], cp[6]);
445 let d1 = CubicBez::new(cp[0], cp[1], cp[2], cp[3]);
446 let d2 = CubicBez::new(cp[9], cp[8], cp[7], cp[6]);
447
448 let sc = (1.0 - v) * c1.eval(u).to_vec2() + v * c2.eval(u).to_vec2();
449 let sd = (1.0 - u) * d1.eval(v).to_vec2() + u * d2.eval(v).to_vec2();
450 let sb = (1.0 - v) * ((1.0 - u) * c1.eval(0.0).to_vec2() + u * c1.eval(1.0).to_vec2())
451 + v * ((1.0 - u) * c2.eval(0.0).to_vec2() + u * c2.eval(1.0).to_vec2());
452
453 (sc + sd - sb).to_point()
454 }
455
456 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
458 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
459 }
460
461 pub fn interpolate(&self, pos: Point) -> ColorComponents {
463 let (u, v) = (pos.x, pos.y);
464 let (c0, c1, c2, c3) = {
465 (
466 &self.colors[0],
467 &self.colors[1],
468 &self.colors[2],
469 &self.colors[3],
470 )
471 };
472
473 let mut result = SmallVec::new();
474 for i in 0..c0.len() {
475 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
476 + u * (1.0 - v) * c3[i] as f64
477 + u * v * c2[i] as f64
478 + (1.0 - u) * v * c1[i] as f64;
479 result.push(val as f32);
480 }
481
482 result
483 }
484}
485
486impl TensorProductPatch {
487 fn bernstein(i: usize, t: f64) -> f64 {
489 match i {
490 0 => (1.0 - t).powi(3),
491 1 => 3.0 * t * (1.0 - t).powi(2),
492 2 => 3.0 * t.powi(2) * (1.0 - t),
493 3 => t.powi(3),
494 _ => 0.0,
495 }
496 }
497
498 pub fn map_coordinate(&self, p: Point) -> Point {
500 let (u, v) = (p.x, p.y);
501
502 let mut x = 0.0;
503 let mut y = 0.0;
504
505 fn idx(i: usize, j: usize) -> usize {
506 match (i, j) {
507 (0, 0) => 0,
508 (0, 1) => 1,
509 (0, 2) => 2,
510 (0, 3) => 3,
511 (1, 0) => 11,
512 (1, 1) => 12,
513 (1, 2) => 13,
514 (1, 3) => 4,
515 (2, 0) => 10,
516 (2, 1) => 15,
517 (2, 2) => 14,
518 (2, 3) => 5,
519 (3, 0) => 9,
520 (3, 1) => 8,
521 (3, 2) => 7,
522 (3, 3) => 6,
523 _ => unreachable!("idx({i},{j}) outside 0..4 × 0..4"),
527 }
528 }
529
530 for i in 0..4 {
531 for j in 0..4 {
532 let control_point_idx = idx(i, j);
533 let basis = Self::bernstein(i, u) * Self::bernstein(j, v);
534
535 x += self.control_points[control_point_idx].x * basis;
536 y += self.control_points[control_point_idx].y * basis;
537 }
538 }
539
540 Point::new(x, y)
541 }
542
543 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
545 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
546 }
547
548 pub fn interpolate(&self, pos: Point) -> ColorComponents {
550 let (u, v) = (pos.x, pos.y);
551 let (c0, c1, c2, c3) = {
552 (
553 &self.colors[0],
554 &self.colors[1],
555 &self.colors[2],
556 &self.colors[3],
557 )
558 };
559
560 let mut result = SmallVec::new();
561 for i in 0..c0.len() {
562 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
563 + u * (1.0 - v) * c3[i] as f64
564 + u * v * c2[i] as f64
565 + (1.0 - u) * v * c1[i] as f64;
566 result.push(val as f32);
567 }
568
569 result
570 }
571}
572
573fn read_free_form_triangles(
574 data: &[u8],
575 bpf: u8,
576 bp_cord: u8,
577 bp_comp: u8,
578 has_function: bool,
579 decode: &[f32],
580) -> Option<Vec<Triangle>> {
581 let mut triangles = vec![];
582
583 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
584 let mut reader = BitReader::new(data);
585 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
586
587 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
588 helpers.read_triangle_vertex(reader, bpf, has_function, decode)
589 };
590
591 let mut a = None;
592 let mut b = None;
593 let mut c = None;
594
595 loop {
596 let Some(first) = read_single(&mut reader) else {
597 break;
598 };
599
600 if first.flag == 0 {
601 let second = read_single(&mut reader)?;
602 let third = read_single(&mut reader)?;
603
604 a = Some(first.clone());
605 b = Some(second.clone());
606 c = Some(third.clone());
607 } else if first.flag == 1 {
608 a = Some(b.clone()?);
609 b = Some(c.clone()?);
610 c = Some(first);
611 } else if first.flag == 2 {
612 b = Some(c.clone()?);
613 c = Some(first);
614 }
615
616 let (p0, p1, p2) = (a.clone()?, b.clone()?, c.clone()?);
617
618 if p0.point.nearly_same(p1.point) || p1.point.nearly_same(p2.point) {
619 continue;
620 }
621
622 triangles.push(Triangle::new(a.clone()?, b.clone()?, c.clone()?));
623 }
624
625 Some(triangles)
626}
627
628struct InterpolationHelpers {
630 bp_coord: u8,
631 bp_comp: u8,
632 coord_max: f32,
633 comp_max: f32,
634 x_min: f32,
635 x_max: f32,
636 y_min: f32,
637 y_max: f32,
638}
639
640impl InterpolationHelpers {
641 fn new(bp_coord: u8, bp_comp: u8, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> Self {
642 let coord_max = 2.0_f32.powi(bp_coord as i32) - 1.0;
643 let comp_max = 2.0_f32.powi(bp_comp as i32) - 1.0;
644 Self {
645 bp_coord,
646 bp_comp,
647 coord_max,
648 comp_max,
649 x_min,
650 x_max,
651 y_min,
652 y_max,
653 }
654 }
655
656 fn interpolate_coord(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
657 interpolate(n as f32, 0.0, self.coord_max, d_min, d_max)
658 }
659
660 fn interpolate_comp(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
661 interpolate(n as f32, 0.0, self.comp_max, d_min, d_max)
662 }
663
664 fn read_point(&self, reader: &mut BitReader<'_>) -> Option<Point> {
665 let x = self.interpolate_coord(reader.read(self.bp_coord)?, self.x_min, self.x_max);
666 let y = self.interpolate_coord(reader.read(self.bp_coord)?, self.y_min, self.y_max);
667 Some(Point::new(x as f64, y as f64))
668 }
669
670 fn read_colors(
671 &self,
672 reader: &mut BitReader<'_>,
673 has_function: bool,
674 decode: &[f32],
675 ) -> Option<ColorComponents> {
676 let mut colors = smallvec![];
677 if has_function {
678 colors.push(self.interpolate_comp(
679 reader.read(self.bp_comp)?,
680 *decode.first()?,
681 *decode.get(1)?,
682 ));
683 } else {
684 let num_components = decode.len() / 2;
685 for (_, decode) in (0..num_components).zip(decode.chunks_exact(2)) {
686 colors.push(self.interpolate_comp(
687 reader.read(self.bp_comp)?,
688 decode[0],
689 decode[1],
690 ));
691 }
692 }
693 Some(colors)
694 }
695
696 fn read_triangle_vertex(
697 &self,
698 reader: &mut BitReader<'_>,
699 bpf: u8,
700 has_function: bool,
701 decode: &[f32],
702 ) -> Option<TriangleVertex> {
703 let flag = reader.read(bpf)?;
704 let point = self.read_point(reader)?;
705 let colors = self.read_colors(reader, has_function, decode)?;
706 reader.align();
707
708 Some(TriangleVertex {
709 flag,
710 point,
711 colors,
712 })
713 }
714}
715
716fn split_decode(decode: &[f32]) -> Option<([f32; 4], &[f32])> {
718 decode.split_first_chunk::<4>().map(|(a, b)| (*a, b))
719}
720
721fn generate_patch_triangles<F, I>(map_coordinate: F, interpolate: I, buffer: &mut Vec<Triangle>)
723where
724 F: Fn(Point) -> Point,
725 I: Fn(Point) -> ColorComponents,
726{
727 const GRID_SIZE: usize = 20;
728 let mut grid = vec![vec![Point::ZERO; GRID_SIZE]; GRID_SIZE];
729
730 for i in 0..GRID_SIZE {
732 for j in 0..GRID_SIZE {
733 let u = i as f64 / (GRID_SIZE - 1) as f64; let v = j as f64 / (GRID_SIZE - 1) as f64; let unit_point = Point::new(u, v);
738 grid[i][j] = map_coordinate(unit_point);
739 }
740 }
741
742 for i in 0..(GRID_SIZE - 1) {
743 for j in 0..(GRID_SIZE - 1) {
744 let p00 = grid[i][j];
745 let p10 = grid[i + 1][j];
746 let p01 = grid[i][j + 1];
747 let p11 = grid[i + 1][j + 1];
748
749 let u0 = i as f64 / (GRID_SIZE - 1) as f64;
751 let u1 = (i + 1) as f64 / (GRID_SIZE - 1) as f64;
752 let v0 = j as f64 / (GRID_SIZE - 1) as f64;
753 let v1 = (j + 1) as f64 / (GRID_SIZE - 1) as f64;
754
755 let v00 = TriangleVertex {
757 flag: 0,
758 point: p00,
759 colors: interpolate(Point::new(u0, v0)),
760 };
761 let v10 = TriangleVertex {
762 flag: 0,
763 point: p10,
764 colors: interpolate(Point::new(u1, v0)),
765 };
766 let v01 = TriangleVertex {
767 flag: 0,
768 point: p01,
769 colors: interpolate(Point::new(u0, v1)),
770 };
771 let v11 = TriangleVertex {
772 flag: 0,
773 point: p11,
774 colors: interpolate(Point::new(u1, v1)),
775 };
776
777 let inflate_point = |p: Point, mid: Point| -> Point {
778 const INFLATION_FACTOR: f64 = 1.025;
779 mid + (p - mid) * INFLATION_FACTOR
780 };
781
782 let inflate = |mut triangle: Triangle| {
785 let mid = triangle.kurbo_tri.centroid();
786 triangle.p0.point = inflate_point(triangle.p0.point, mid);
787 triangle.p1.point = inflate_point(triangle.p1.point, mid);
788 triangle.p2.point = inflate_point(triangle.p2.point, mid);
789
790 triangle
791 };
792
793 buffer.push(inflate(Triangle::new(
794 v00.clone(),
795 v10.clone(),
796 v01.clone(),
797 )));
798 buffer.push(inflate(Triangle::new(
799 v10.clone(),
800 v11.clone(),
801 v01.clone(),
802 )));
803 }
804 }
805}
806
807fn read_lattice_triangles(
808 data: &[u8],
809 bp_cord: u8,
810 bp_comp: u8,
811 has_function: bool,
812 vertices_per_row: u32,
813 decode: &[f32],
814) -> Option<Vec<Triangle>> {
815 let mut lattices = vec![];
816
817 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
818 let mut reader = BitReader::new(data);
819 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
820
821 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
822 let point = helpers.read_point(reader)?;
823 let colors = helpers.read_colors(reader, has_function, decode)?;
824 reader.align();
825
826 Some(TriangleVertex {
827 flag: 0,
828 point,
829 colors,
830 })
831 };
832
833 'outer: loop {
834 let mut single_row = vec![];
835
836 for _ in 0..vertices_per_row {
837 let Some(next) = read_single(&mut reader) else {
838 break 'outer;
839 };
840
841 single_row.push(next);
842 }
843
844 lattices.push(single_row);
845 }
846
847 let mut triangles = vec![];
848
849 for i in 0..lattices.len().saturating_sub(1) {
850 for j in 0..(vertices_per_row as usize).saturating_sub(1) {
851 triangles.push(Triangle::new(
852 lattices[i][j].clone(),
853 lattices[i + 1][j].clone(),
854 lattices[i][j + 1].clone(),
855 ));
856
857 triangles.push(Triangle::new(
858 lattices[i + 1][j + 1].clone(),
859 lattices[i + 1][j].clone(),
860 lattices[i][j + 1].clone(),
861 ));
862 }
863 }
864
865 Some(triangles)
866}
867
868fn read_coons_patch_mesh(
869 data: &[u8],
870 bpf: u8,
871 bp_coord: u8,
872 bp_comp: u8,
873 has_function: bool,
874 decode: &[f32],
875) -> Option<Vec<CoonsPatch>> {
876 read_patch_mesh(
877 data,
878 bpf,
879 bp_coord,
880 bp_comp,
881 has_function,
882 decode,
883 12,
884 |control_points, colors| {
885 let mut coons_points = [Point::ZERO; 12];
886 coons_points.copy_from_slice(&control_points[0..12]);
887 CoonsPatch {
888 control_points: coons_points,
889 colors,
890 }
891 },
892 )
893}
894
895#[allow(clippy::too_many_arguments)]
897fn read_patch_mesh<P, F>(
898 data: &[u8],
899 bpf: u8,
900 bp_coord: u8,
901 bp_comp: u8,
902 has_function: bool,
903 decode: &[f32],
904 control_points_count: usize,
905 create_patch: F,
906) -> Option<Vec<P>>
907where
908 F: Fn([Point; 16], [ColorComponents; 4]) -> P,
909{
910 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
911 let mut reader = BitReader::new(data);
912 let helpers = InterpolationHelpers::new(bp_coord, bp_comp, x_min, x_max, y_min, y_max);
913
914 let read_colors = |reader: &mut BitReader<'_>| -> Option<ColorComponents> {
915 helpers.read_colors(reader, has_function, decode)
916 };
917
918 let mut prev_patch_points: Option<Vec<Point>> = None;
919 let mut prev_patch_colors: Option<[ColorComponents; 4]> = None;
920 let mut patches = vec![];
921
922 while let Some(flag) = reader.read(bpf) {
923 let mut control_points = vec![Point::ZERO; 16]; let mut colors = [smallvec![], smallvec![], smallvec![], smallvec![]];
925
926 match flag {
927 0 => {
928 for i in 0..control_points_count {
929 control_points[i] = helpers.read_point(&mut reader)?;
930 }
931
932 for i in 0..4 {
933 colors[i] = read_colors(&mut reader)?;
934 }
935
936 prev_patch_points = Some(control_points.clone());
937 prev_patch_colors = Some(colors.clone());
938 }
939 1..=3 => {
940 let prev_points = prev_patch_points.as_ref()?;
941 let prev_colors = prev_patch_colors.as_ref()?;
942
943 copy_patch_control_points(flag, prev_points, &mut control_points);
944
945 match flag {
946 1 => {
947 colors[0] = prev_colors[1].clone();
948 colors[1] = prev_colors[2].clone();
949 }
950 2 => {
951 colors[0] = prev_colors[2].clone();
952 colors[1] = prev_colors[3].clone();
953 }
954 3 => {
955 colors[0] = prev_colors[3].clone();
956 colors[1] = prev_colors[0].clone();
957 }
958 _ => unreachable!(),
959 }
960
961 for i in 4..control_points_count {
962 control_points[i] = helpers.read_point(&mut reader)?;
963 }
964
965 colors[2] = read_colors(&mut reader)?;
966 colors[3] = read_colors(&mut reader)?;
967
968 prev_patch_points = Some(control_points.clone());
969 prev_patch_colors = Some(colors.clone());
970 }
971 _ => break,
972 }
973
974 let mut fixed_points = [Point::ZERO; 16];
975 for i in 0..16 {
976 if i < control_points.len() {
977 fixed_points[i] = control_points[i];
978 }
979 }
980
981 patches.push(create_patch(fixed_points, colors));
982 }
983 Some(patches)
984}
985
986fn copy_patch_control_points(
987 flag: u32,
988 prev_control_points: &[Point],
989 control_points: &mut [Point],
990) {
991 match flag {
992 1 => {
993 control_points[0] = prev_control_points[3];
994 control_points[1] = prev_control_points[4];
995 control_points[2] = prev_control_points[5];
996 control_points[3] = prev_control_points[6];
997 }
998 2 => {
999 control_points[0] = prev_control_points[6];
1000 control_points[1] = prev_control_points[7];
1001 control_points[2] = prev_control_points[8];
1002 control_points[3] = prev_control_points[9];
1003 }
1004 3 => {
1005 control_points[0] = prev_control_points[9];
1006 control_points[1] = prev_control_points[10];
1007 control_points[2] = prev_control_points[11];
1008 control_points[3] = prev_control_points[0];
1009 }
1010 _ => {}
1011 }
1012}
1013
1014fn read_tensor_product_patch_mesh(
1015 data: &[u8],
1016 bpf: u8,
1017 bp_coord: u8,
1018 bp_comp: u8,
1019 has_function: bool,
1020 decode: &[f32],
1021) -> Option<Vec<TensorProductPatch>> {
1022 read_patch_mesh(
1023 data,
1024 bpf,
1025 bp_coord,
1026 bp_comp,
1027 has_function,
1028 decode,
1029 16,
1030 |control_points, colors| TensorProductPatch {
1031 control_points,
1032 colors,
1033 },
1034 )
1035}
1036
1037fn read_function(
1038 dict: &Dict<'_>,
1039 color_space: &ColorSpace,
1040 warning_sink: &WarningSinkFn,
1041) -> Option<ShadingFunction> {
1042 if let Some(arr) = dict.get::<Array<'_>>(FUNCTION) {
1043 let arr: Option<SmallVec<_>> = arr
1044 .iter::<Object<'_>>()
1045 .map(|o| Function::new_with_sink(&o, warning_sink))
1046 .collect();
1047 let arr = arr?;
1048
1049 if arr.len() != color_space.num_components() as usize {
1050 warn!("function array of shading has wrong size");
1051
1052 return None;
1053 }
1054
1055 Some(ShadingFunction::Multiple(arr))
1056 } else if let Some(obj) = dict.get::<Object<'_>>(FUNCTION) {
1057 Some(ShadingFunction::Single(Function::new_with_sink(
1058 &obj,
1059 warning_sink,
1060 )?))
1061 } else {
1062 None
1063 }
1064}