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