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 _ => panic!("Invalid index"),
524 }
525 }
526
527 for i in 0..4 {
528 for j in 0..4 {
529 let control_point_idx = idx(i, j);
530 let basis = Self::bernstein(i, u) * Self::bernstein(j, v);
531
532 x += self.control_points[control_point_idx].x * basis;
533 y += self.control_points[control_point_idx].y * basis;
534 }
535 }
536
537 Point::new(x, y)
538 }
539
540 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
542 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
543 }
544
545 pub fn interpolate(&self, pos: Point) -> ColorComponents {
547 let (u, v) = (pos.x, pos.y);
548 let (c0, c1, c2, c3) = {
549 (
550 &self.colors[0],
551 &self.colors[1],
552 &self.colors[2],
553 &self.colors[3],
554 )
555 };
556
557 let mut result = SmallVec::new();
558 for i in 0..c0.len() {
559 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
560 + u * (1.0 - v) * c3[i] as f64
561 + u * v * c2[i] as f64
562 + (1.0 - u) * v * c1[i] as f64;
563 result.push(val as f32);
564 }
565
566 result
567 }
568}
569
570fn read_free_form_triangles(
571 data: &[u8],
572 bpf: u8,
573 bp_cord: u8,
574 bp_comp: u8,
575 has_function: bool,
576 decode: &[f32],
577) -> Option<Vec<Triangle>> {
578 let mut triangles = vec![];
579
580 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
581 let mut reader = BitReader::new(data);
582 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
583
584 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
585 helpers.read_triangle_vertex(reader, bpf, has_function, decode)
586 };
587
588 let mut a = None;
589 let mut b = None;
590 let mut c = None;
591
592 loop {
593 let Some(first) = read_single(&mut reader) else {
594 break;
595 };
596
597 if first.flag == 0 {
598 let second = read_single(&mut reader)?;
599 let third = read_single(&mut reader)?;
600
601 a = Some(first.clone());
602 b = Some(second.clone());
603 c = Some(third.clone());
604 } else if first.flag == 1 {
605 a = Some(b.clone()?);
606 b = Some(c.clone()?);
607 c = Some(first);
608 } else if first.flag == 2 {
609 b = Some(c.clone()?);
610 c = Some(first);
611 }
612
613 let (p0, p1, p2) = (a.clone()?, b.clone()?, c.clone()?);
614
615 if p0.point.nearly_same(p1.point) || p1.point.nearly_same(p2.point) {
616 continue;
617 }
618
619 triangles.push(Triangle::new(a.clone()?, b.clone()?, c.clone()?));
620 }
621
622 Some(triangles)
623}
624
625struct InterpolationHelpers {
627 bp_coord: u8,
628 bp_comp: u8,
629 coord_max: f32,
630 comp_max: f32,
631 x_min: f32,
632 x_max: f32,
633 y_min: f32,
634 y_max: f32,
635}
636
637impl InterpolationHelpers {
638 fn new(bp_coord: u8, bp_comp: u8, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> Self {
639 let coord_max = 2.0_f32.powi(bp_coord as i32) - 1.0;
640 let comp_max = 2.0_f32.powi(bp_comp as i32) - 1.0;
641 Self {
642 bp_coord,
643 bp_comp,
644 coord_max,
645 comp_max,
646 x_min,
647 x_max,
648 y_min,
649 y_max,
650 }
651 }
652
653 fn interpolate_coord(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
654 interpolate(n as f32, 0.0, self.coord_max, d_min, d_max)
655 }
656
657 fn interpolate_comp(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
658 interpolate(n as f32, 0.0, self.comp_max, d_min, d_max)
659 }
660
661 fn read_point(&self, reader: &mut BitReader<'_>) -> Option<Point> {
662 let x = self.interpolate_coord(reader.read(self.bp_coord)?, self.x_min, self.x_max);
663 let y = self.interpolate_coord(reader.read(self.bp_coord)?, self.y_min, self.y_max);
664 Some(Point::new(x as f64, y as f64))
665 }
666
667 fn read_colors(
668 &self,
669 reader: &mut BitReader<'_>,
670 has_function: bool,
671 decode: &[f32],
672 ) -> Option<ColorComponents> {
673 let mut colors = smallvec![];
674 if has_function {
675 colors.push(self.interpolate_comp(
676 reader.read(self.bp_comp)?,
677 *decode.first()?,
678 *decode.get(1)?,
679 ));
680 } else {
681 let num_components = decode.len() / 2;
682 for (_, decode) in (0..num_components).zip(decode.chunks_exact(2)) {
683 colors.push(self.interpolate_comp(
684 reader.read(self.bp_comp)?,
685 decode[0],
686 decode[1],
687 ));
688 }
689 }
690 Some(colors)
691 }
692
693 fn read_triangle_vertex(
694 &self,
695 reader: &mut BitReader<'_>,
696 bpf: u8,
697 has_function: bool,
698 decode: &[f32],
699 ) -> Option<TriangleVertex> {
700 let flag = reader.read(bpf)?;
701 let point = self.read_point(reader)?;
702 let colors = self.read_colors(reader, has_function, decode)?;
703 reader.align();
704
705 Some(TriangleVertex {
706 flag,
707 point,
708 colors,
709 })
710 }
711}
712
713fn split_decode(decode: &[f32]) -> Option<([f32; 4], &[f32])> {
715 decode.split_first_chunk::<4>().map(|(a, b)| (*a, b))
716}
717
718fn generate_patch_triangles<F, I>(map_coordinate: F, interpolate: I, buffer: &mut Vec<Triangle>)
720where
721 F: Fn(Point) -> Point,
722 I: Fn(Point) -> ColorComponents,
723{
724 const GRID_SIZE: usize = 20;
725 let mut grid = vec![vec![Point::ZERO; GRID_SIZE]; GRID_SIZE];
726
727 for i in 0..GRID_SIZE {
729 for j in 0..GRID_SIZE {
730 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);
735 grid[i][j] = map_coordinate(unit_point);
736 }
737 }
738
739 for i in 0..(GRID_SIZE - 1) {
740 for j in 0..(GRID_SIZE - 1) {
741 let p00 = grid[i][j];
742 let p10 = grid[i + 1][j];
743 let p01 = grid[i][j + 1];
744 let p11 = grid[i + 1][j + 1];
745
746 let u0 = i as f64 / (GRID_SIZE - 1) as f64;
748 let u1 = (i + 1) as f64 / (GRID_SIZE - 1) as f64;
749 let v0 = j as f64 / (GRID_SIZE - 1) as f64;
750 let v1 = (j + 1) as f64 / (GRID_SIZE - 1) as f64;
751
752 let v00 = TriangleVertex {
754 flag: 0,
755 point: p00,
756 colors: interpolate(Point::new(u0, v0)),
757 };
758 let v10 = TriangleVertex {
759 flag: 0,
760 point: p10,
761 colors: interpolate(Point::new(u1, v0)),
762 };
763 let v01 = TriangleVertex {
764 flag: 0,
765 point: p01,
766 colors: interpolate(Point::new(u0, v1)),
767 };
768 let v11 = TriangleVertex {
769 flag: 0,
770 point: p11,
771 colors: interpolate(Point::new(u1, v1)),
772 };
773
774 let inflate_point = |p: Point, mid: Point| -> Point {
775 const INFLATION_FACTOR: f64 = 1.025;
776 mid + (p - mid) * INFLATION_FACTOR
777 };
778
779 let inflate = |mut triangle: Triangle| {
782 let mid = triangle.kurbo_tri.centroid();
783 triangle.p0.point = inflate_point(triangle.p0.point, mid);
784 triangle.p1.point = inflate_point(triangle.p1.point, mid);
785 triangle.p2.point = inflate_point(triangle.p2.point, mid);
786
787 triangle
788 };
789
790 buffer.push(inflate(Triangle::new(
791 v00.clone(),
792 v10.clone(),
793 v01.clone(),
794 )));
795 buffer.push(inflate(Triangle::new(
796 v10.clone(),
797 v11.clone(),
798 v01.clone(),
799 )));
800 }
801 }
802}
803
804fn read_lattice_triangles(
805 data: &[u8],
806 bp_cord: u8,
807 bp_comp: u8,
808 has_function: bool,
809 vertices_per_row: u32,
810 decode: &[f32],
811) -> Option<Vec<Triangle>> {
812 let mut lattices = vec![];
813
814 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
815 let mut reader = BitReader::new(data);
816 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
817
818 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
819 let point = helpers.read_point(reader)?;
820 let colors = helpers.read_colors(reader, has_function, decode)?;
821 reader.align();
822
823 Some(TriangleVertex {
824 flag: 0,
825 point,
826 colors,
827 })
828 };
829
830 'outer: loop {
831 let mut single_row = vec![];
832
833 for _ in 0..vertices_per_row {
834 let Some(next) = read_single(&mut reader) else {
835 break 'outer;
836 };
837
838 single_row.push(next);
839 }
840
841 lattices.push(single_row);
842 }
843
844 let mut triangles = vec![];
845
846 for i in 0..lattices.len().saturating_sub(1) {
847 for j in 0..(vertices_per_row as usize).saturating_sub(1) {
848 triangles.push(Triangle::new(
849 lattices[i][j].clone(),
850 lattices[i + 1][j].clone(),
851 lattices[i][j + 1].clone(),
852 ));
853
854 triangles.push(Triangle::new(
855 lattices[i + 1][j + 1].clone(),
856 lattices[i + 1][j].clone(),
857 lattices[i][j + 1].clone(),
858 ));
859 }
860 }
861
862 Some(triangles)
863}
864
865fn read_coons_patch_mesh(
866 data: &[u8],
867 bpf: u8,
868 bp_coord: u8,
869 bp_comp: u8,
870 has_function: bool,
871 decode: &[f32],
872) -> Option<Vec<CoonsPatch>> {
873 read_patch_mesh(
874 data,
875 bpf,
876 bp_coord,
877 bp_comp,
878 has_function,
879 decode,
880 12,
881 |control_points, colors| {
882 let mut coons_points = [Point::ZERO; 12];
883 coons_points.copy_from_slice(&control_points[0..12]);
884 CoonsPatch {
885 control_points: coons_points,
886 colors,
887 }
888 },
889 )
890}
891
892#[allow(clippy::too_many_arguments)]
894fn read_patch_mesh<P, F>(
895 data: &[u8],
896 bpf: u8,
897 bp_coord: u8,
898 bp_comp: u8,
899 has_function: bool,
900 decode: &[f32],
901 control_points_count: usize,
902 create_patch: F,
903) -> Option<Vec<P>>
904where
905 F: Fn([Point; 16], [ColorComponents; 4]) -> P,
906{
907 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
908 let mut reader = BitReader::new(data);
909 let helpers = InterpolationHelpers::new(bp_coord, bp_comp, x_min, x_max, y_min, y_max);
910
911 let read_colors = |reader: &mut BitReader<'_>| -> Option<ColorComponents> {
912 helpers.read_colors(reader, has_function, decode)
913 };
914
915 let mut prev_patch_points: Option<Vec<Point>> = None;
916 let mut prev_patch_colors: Option<[ColorComponents; 4]> = None;
917 let mut patches = vec![];
918
919 while let Some(flag) = reader.read(bpf) {
920 let mut control_points = vec![Point::ZERO; 16]; let mut colors = [smallvec![], smallvec![], smallvec![], smallvec![]];
922
923 match flag {
924 0 => {
925 for i in 0..control_points_count {
926 control_points[i] = helpers.read_point(&mut reader)?;
927 }
928
929 for i in 0..4 {
930 colors[i] = read_colors(&mut reader)?;
931 }
932
933 prev_patch_points = Some(control_points.clone());
934 prev_patch_colors = Some(colors.clone());
935 }
936 1..=3 => {
937 let prev_points = prev_patch_points.as_ref()?;
938 let prev_colors = prev_patch_colors.as_ref()?;
939
940 copy_patch_control_points(flag, prev_points, &mut control_points);
941
942 match flag {
943 1 => {
944 colors[0] = prev_colors[1].clone();
945 colors[1] = prev_colors[2].clone();
946 }
947 2 => {
948 colors[0] = prev_colors[2].clone();
949 colors[1] = prev_colors[3].clone();
950 }
951 3 => {
952 colors[0] = prev_colors[3].clone();
953 colors[1] = prev_colors[0].clone();
954 }
955 _ => unreachable!(),
956 }
957
958 for i in 4..control_points_count {
959 control_points[i] = helpers.read_point(&mut reader)?;
960 }
961
962 colors[2] = read_colors(&mut reader)?;
963 colors[3] = read_colors(&mut reader)?;
964
965 prev_patch_points = Some(control_points.clone());
966 prev_patch_colors = Some(colors.clone());
967 }
968 _ => break,
969 }
970
971 let mut fixed_points = [Point::ZERO; 16];
972 for i in 0..16 {
973 if i < control_points.len() {
974 fixed_points[i] = control_points[i];
975 }
976 }
977
978 patches.push(create_patch(fixed_points, colors));
979 }
980 Some(patches)
981}
982
983fn copy_patch_control_points(
984 flag: u32,
985 prev_control_points: &[Point],
986 control_points: &mut [Point],
987) {
988 match flag {
989 1 => {
990 control_points[0] = prev_control_points[3];
991 control_points[1] = prev_control_points[4];
992 control_points[2] = prev_control_points[5];
993 control_points[3] = prev_control_points[6];
994 }
995 2 => {
996 control_points[0] = prev_control_points[6];
997 control_points[1] = prev_control_points[7];
998 control_points[2] = prev_control_points[8];
999 control_points[3] = prev_control_points[9];
1000 }
1001 3 => {
1002 control_points[0] = prev_control_points[9];
1003 control_points[1] = prev_control_points[10];
1004 control_points[2] = prev_control_points[11];
1005 control_points[3] = prev_control_points[0];
1006 }
1007 _ => {}
1008 }
1009}
1010
1011fn read_tensor_product_patch_mesh(
1012 data: &[u8],
1013 bpf: u8,
1014 bp_coord: u8,
1015 bp_comp: u8,
1016 has_function: bool,
1017 decode: &[f32],
1018) -> Option<Vec<TensorProductPatch>> {
1019 read_patch_mesh(
1020 data,
1021 bpf,
1022 bp_coord,
1023 bp_comp,
1024 has_function,
1025 decode,
1026 16,
1027 |control_points, colors| TensorProductPatch {
1028 control_points,
1029 colors,
1030 },
1031 )
1032}
1033
1034fn read_function(
1035 dict: &Dict<'_>,
1036 color_space: &ColorSpace,
1037 warning_sink: &WarningSinkFn,
1038) -> Option<ShadingFunction> {
1039 if let Some(arr) = dict.get::<Array<'_>>(FUNCTION) {
1040 let arr: Option<SmallVec<_>> = arr
1041 .iter::<Object<'_>>()
1042 .map(|o| Function::new_with_sink(&o, warning_sink))
1043 .collect();
1044 let arr = arr?;
1045
1046 if arr.len() != color_space.num_components() as usize {
1047 warn!("function array of shading has wrong size");
1048
1049 return None;
1050 }
1051
1052 Some(ShadingFunction::Multiple(arr))
1053 } else if let Some(obj) = dict.get::<Object<'_>>(FUNCTION) {
1054 Some(ShadingFunction::Single(Function::new_with_sink(
1055 &obj,
1056 warning_sink,
1057 )?))
1058 } else {
1059 None
1060 }
1061}