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 hayro_syntax::bit_reader::BitReader;
11use hayro_syntax::object::Array;
12use hayro_syntax::object::Dict;
13use hayro_syntax::object::Object;
14use hayro_syntax::object::Rect;
15use hayro_syntax::object::Stream;
16use hayro_syntax::object::dict::keys::{
17 BACKGROUND, BBOX, BITS_PER_COMPONENT, BITS_PER_COORDINATE, BITS_PER_FLAG, COLORSPACE, COORDS,
18 DECODE, DOMAIN, EXTEND, FUNCTION, MATRIX, SHADING_TYPE, VERTICES_PER_ROW,
19};
20use kurbo::{Affine, BezPath, CubicBez, ParamCurve, Point, Shape};
21use log::warn;
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
397#[derive(Clone, Debug)]
399pub struct CoonsPatch {
400 pub control_points: [Point; 12],
402 pub colors: [ColorComponents; 4],
404}
405
406#[derive(Clone, Debug)]
408pub struct TensorProductPatch {
409 pub control_points: [Point; 16],
411 pub colors: [ColorComponents; 4],
413}
414
415impl CoonsPatch {
416 pub fn map_coordinate(&self, p: Point) -> Point {
418 let (u, v) = (p.x, p.y);
419
420 let cp = &self.control_points;
421
422 let c1 = CubicBez::new(cp[0], cp[11], cp[10], cp[9]);
423 let c2 = CubicBez::new(cp[3], cp[4], cp[5], cp[6]);
424 let d1 = CubicBez::new(cp[0], cp[1], cp[2], cp[3]);
425 let d2 = CubicBez::new(cp[9], cp[8], cp[7], cp[6]);
426
427 let sc = (1.0 - v) * c1.eval(u).to_vec2() + v * c2.eval(u).to_vec2();
428 let sd = (1.0 - u) * d1.eval(v).to_vec2() + u * d2.eval(v).to_vec2();
429 let sb = (1.0 - v) * ((1.0 - u) * c1.eval(0.0).to_vec2() + u * c1.eval(1.0).to_vec2())
430 + v * ((1.0 - u) * c2.eval(0.0).to_vec2() + u * c2.eval(1.0).to_vec2());
431
432 (sc + sd - sb).to_point()
433 }
434
435 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
437 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
438 }
439
440 pub fn interpolate(&self, pos: Point) -> ColorComponents {
442 let (u, v) = (pos.x, pos.y);
443 let (c0, c1, c2, c3) = {
444 (
445 &self.colors[0],
446 &self.colors[1],
447 &self.colors[2],
448 &self.colors[3],
449 )
450 };
451
452 let mut result = SmallVec::new();
453 for i in 0..c0.len() {
454 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
455 + u * (1.0 - v) * c3[i] as f64
456 + u * v * c2[i] as f64
457 + (1.0 - u) * v * c1[i] as f64;
458 result.push(val as f32);
459 }
460
461 result
462 }
463}
464
465impl TensorProductPatch {
466 fn bernstein(i: usize, t: f64) -> f64 {
468 match i {
469 0 => (1.0 - t).powi(3),
470 1 => 3.0 * t * (1.0 - t).powi(2),
471 2 => 3.0 * t.powi(2) * (1.0 - t),
472 3 => t.powi(3),
473 _ => 0.0,
474 }
475 }
476
477 pub fn map_coordinate(&self, p: Point) -> Point {
479 let (u, v) = (p.x, p.y);
480
481 let mut x = 0.0;
482 let mut y = 0.0;
483
484 fn idx(i: usize, j: usize) -> usize {
485 match (i, j) {
486 (0, 0) => 0,
487 (0, 1) => 1,
488 (0, 2) => 2,
489 (0, 3) => 3,
490 (1, 0) => 11,
491 (1, 1) => 12,
492 (1, 2) => 13,
493 (1, 3) => 4,
494 (2, 0) => 10,
495 (2, 1) => 15,
496 (2, 2) => 14,
497 (2, 3) => 5,
498 (3, 0) => 9,
499 (3, 1) => 8,
500 (3, 2) => 7,
501 (3, 3) => 6,
502 _ => panic!("Invalid index"),
503 }
504 }
505
506 for i in 0..4 {
507 for j in 0..4 {
508 let control_point_idx = idx(i, j);
509 let basis = Self::bernstein(i, u) * Self::bernstein(j, v);
510
511 x += self.control_points[control_point_idx].x * basis;
512 y += self.control_points[control_point_idx].y * basis;
513 }
514 }
515
516 Point::new(x, y)
517 }
518
519 pub fn to_triangles(&self, buffer: &mut Vec<Triangle>) {
521 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p), buffer);
522 }
523
524 pub fn interpolate(&self, pos: Point) -> ColorComponents {
526 let (u, v) = (pos.x, pos.y);
527 let (c0, c1, c2, c3) = {
528 (
529 &self.colors[0],
530 &self.colors[1],
531 &self.colors[2],
532 &self.colors[3],
533 )
534 };
535
536 let mut result = SmallVec::new();
537 for i in 0..c0.len() {
538 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
539 + u * (1.0 - v) * c3[i] as f64
540 + u * v * c2[i] as f64
541 + (1.0 - u) * v * c1[i] as f64;
542 result.push(val as f32);
543 }
544
545 result
546 }
547}
548
549fn read_free_form_triangles(
550 data: &[u8],
551 bpf: u8,
552 bp_cord: u8,
553 bp_comp: u8,
554 has_function: bool,
555 decode: &[f32],
556) -> Option<Vec<Triangle>> {
557 let mut triangles = vec![];
558
559 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
560 let mut reader = BitReader::new(data);
561 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
562
563 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
564 helpers.read_triangle_vertex(reader, bpf, has_function, decode)
565 };
566
567 let mut a = None;
568 let mut b = None;
569 let mut c = None;
570
571 loop {
572 let Some(first) = read_single(&mut reader) else {
573 break;
574 };
575
576 if first.flag == 0 {
577 let second = read_single(&mut reader)?;
578 let third = read_single(&mut reader)?;
579
580 a = Some(first.clone());
581 b = Some(second.clone());
582 c = Some(third.clone());
583 } else if first.flag == 1 {
584 a = Some(b.clone()?);
585 b = Some(c.clone()?);
586 c = Some(first);
587 } else if first.flag == 2 {
588 b = Some(c.clone()?);
589 c = Some(first);
590 }
591
592 let (p0, p1, p2) = (a.clone()?, b.clone()?, c.clone()?);
593
594 if p0.point.nearly_same(p1.point) || p1.point.nearly_same(p2.point) {
595 continue;
596 }
597
598 triangles.push(Triangle::new(a.clone()?, b.clone()?, c.clone()?));
599 }
600
601 Some(triangles)
602}
603
604struct InterpolationHelpers {
606 bp_coord: u8,
607 bp_comp: u8,
608 coord_max: f32,
609 comp_max: f32,
610 x_min: f32,
611 x_max: f32,
612 y_min: f32,
613 y_max: f32,
614}
615
616impl InterpolationHelpers {
617 fn new(bp_coord: u8, bp_comp: u8, x_min: f32, x_max: f32, y_min: f32, y_max: f32) -> Self {
618 let coord_max = 2.0_f32.powi(bp_coord as i32) - 1.0;
619 let comp_max = 2.0_f32.powi(bp_comp as i32) - 1.0;
620 Self {
621 bp_coord,
622 bp_comp,
623 coord_max,
624 comp_max,
625 x_min,
626 x_max,
627 y_min,
628 y_max,
629 }
630 }
631
632 fn interpolate_coord(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
633 interpolate(n as f32, 0.0, self.coord_max, d_min, d_max)
634 }
635
636 fn interpolate_comp(&self, n: u32, d_min: f32, d_max: f32) -> f32 {
637 interpolate(n as f32, 0.0, self.comp_max, d_min, d_max)
638 }
639
640 fn read_point(&self, reader: &mut BitReader<'_>) -> Option<Point> {
641 let x = self.interpolate_coord(reader.read(self.bp_coord)?, self.x_min, self.x_max);
642 let y = self.interpolate_coord(reader.read(self.bp_coord)?, self.y_min, self.y_max);
643 Some(Point::new(x as f64, y as f64))
644 }
645
646 fn read_colors(
647 &self,
648 reader: &mut BitReader<'_>,
649 has_function: bool,
650 decode: &[f32],
651 ) -> Option<ColorComponents> {
652 let mut colors = smallvec![];
653 if has_function {
654 colors.push(self.interpolate_comp(
655 reader.read(self.bp_comp)?,
656 *decode.first()?,
657 *decode.get(1)?,
658 ));
659 } else {
660 let num_components = decode.len() / 2;
661 for (_, decode) in (0..num_components).zip(decode.chunks_exact(2)) {
662 colors.push(self.interpolate_comp(
663 reader.read(self.bp_comp)?,
664 decode[0],
665 decode[1],
666 ));
667 }
668 }
669 Some(colors)
670 }
671
672 fn read_triangle_vertex(
673 &self,
674 reader: &mut BitReader<'_>,
675 bpf: u8,
676 has_function: bool,
677 decode: &[f32],
678 ) -> Option<TriangleVertex> {
679 let flag = reader.read(bpf)?;
680 let point = self.read_point(reader)?;
681 let colors = self.read_colors(reader, has_function, decode)?;
682 reader.align();
683
684 Some(TriangleVertex {
685 flag,
686 point,
687 colors,
688 })
689 }
690}
691
692fn split_decode(decode: &[f32]) -> Option<([f32; 4], &[f32])> {
694 decode.split_first_chunk::<4>().map(|(a, b)| (*a, b))
695}
696
697fn generate_patch_triangles<F, I>(map_coordinate: F, interpolate: I, buffer: &mut Vec<Triangle>)
699where
700 F: Fn(Point) -> Point,
701 I: Fn(Point) -> ColorComponents,
702{
703 const GRID_SIZE: usize = 20;
704 let mut grid = vec![vec![Point::ZERO; GRID_SIZE]; GRID_SIZE];
705
706 for i in 0..GRID_SIZE {
708 for j in 0..GRID_SIZE {
709 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);
714 grid[i][j] = map_coordinate(unit_point);
715 }
716 }
717
718 for i in 0..(GRID_SIZE - 1) {
719 for j in 0..(GRID_SIZE - 1) {
720 let p00 = grid[i][j];
721 let p10 = grid[i + 1][j];
722 let p01 = grid[i][j + 1];
723 let p11 = grid[i + 1][j + 1];
724
725 let u0 = i as f64 / (GRID_SIZE - 1) as f64;
727 let u1 = (i + 1) as f64 / (GRID_SIZE - 1) as f64;
728 let v0 = j as f64 / (GRID_SIZE - 1) as f64;
729 let v1 = (j + 1) as f64 / (GRID_SIZE - 1) as f64;
730
731 let v00 = TriangleVertex {
733 flag: 0,
734 point: p00,
735 colors: interpolate(Point::new(u0, v0)),
736 };
737 let v10 = TriangleVertex {
738 flag: 0,
739 point: p10,
740 colors: interpolate(Point::new(u1, v0)),
741 };
742 let v01 = TriangleVertex {
743 flag: 0,
744 point: p01,
745 colors: interpolate(Point::new(u0, v1)),
746 };
747 let v11 = TriangleVertex {
748 flag: 0,
749 point: p11,
750 colors: interpolate(Point::new(u1, v1)),
751 };
752
753 let inflate_point = |p: Point, mid: Point| -> Point {
754 const INFLATION_FACTOR: f64 = 1.025;
755 mid + (p - mid) * INFLATION_FACTOR
756 };
757
758 let inflate = |mut triangle: Triangle| {
761 let mid = triangle.kurbo_tri.centroid();
762 triangle.p0.point = inflate_point(triangle.p0.point, mid);
763 triangle.p1.point = inflate_point(triangle.p1.point, mid);
764 triangle.p2.point = inflate_point(triangle.p2.point, mid);
765
766 triangle
767 };
768
769 buffer.push(inflate(Triangle::new(
770 v00.clone(),
771 v10.clone(),
772 v01.clone(),
773 )));
774 buffer.push(inflate(Triangle::new(
775 v10.clone(),
776 v11.clone(),
777 v01.clone(),
778 )));
779 }
780 }
781}
782
783fn read_lattice_triangles(
784 data: &[u8],
785 bp_cord: u8,
786 bp_comp: u8,
787 has_function: bool,
788 vertices_per_row: u32,
789 decode: &[f32],
790) -> Option<Vec<Triangle>> {
791 let mut lattices = vec![];
792
793 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
794 let mut reader = BitReader::new(data);
795 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
796
797 let read_single = |reader: &mut BitReader<'_>| -> Option<TriangleVertex> {
798 let point = helpers.read_point(reader)?;
799 let colors = helpers.read_colors(reader, has_function, decode)?;
800 reader.align();
801
802 Some(TriangleVertex {
803 flag: 0,
804 point,
805 colors,
806 })
807 };
808
809 'outer: loop {
810 let mut single_row = vec![];
811
812 for _ in 0..vertices_per_row {
813 let Some(next) = read_single(&mut reader) else {
814 break 'outer;
815 };
816
817 single_row.push(next);
818 }
819
820 lattices.push(single_row);
821 }
822
823 let mut triangles = vec![];
824
825 for i in 0..lattices.len().saturating_sub(1) {
826 for j in 0..(vertices_per_row as usize).saturating_sub(1) {
827 triangles.push(Triangle::new(
828 lattices[i][j].clone(),
829 lattices[i + 1][j].clone(),
830 lattices[i][j + 1].clone(),
831 ));
832
833 triangles.push(Triangle::new(
834 lattices[i + 1][j + 1].clone(),
835 lattices[i + 1][j].clone(),
836 lattices[i][j + 1].clone(),
837 ));
838 }
839 }
840
841 Some(triangles)
842}
843
844fn read_coons_patch_mesh(
845 data: &[u8],
846 bpf: u8,
847 bp_coord: u8,
848 bp_comp: u8,
849 has_function: bool,
850 decode: &[f32],
851) -> Option<Vec<CoonsPatch>> {
852 read_patch_mesh(
853 data,
854 bpf,
855 bp_coord,
856 bp_comp,
857 has_function,
858 decode,
859 12,
860 |control_points, colors| {
861 let mut coons_points = [Point::ZERO; 12];
862 coons_points.copy_from_slice(&control_points[0..12]);
863 CoonsPatch {
864 control_points: coons_points,
865 colors,
866 }
867 },
868 )
869}
870
871#[allow(clippy::too_many_arguments)]
873fn read_patch_mesh<P, F>(
874 data: &[u8],
875 bpf: u8,
876 bp_coord: u8,
877 bp_comp: u8,
878 has_function: bool,
879 decode: &[f32],
880 control_points_count: usize,
881 create_patch: F,
882) -> Option<Vec<P>>
883where
884 F: Fn([Point; 16], [ColorComponents; 4]) -> P,
885{
886 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
887 let mut reader = BitReader::new(data);
888 let helpers = InterpolationHelpers::new(bp_coord, bp_comp, x_min, x_max, y_min, y_max);
889
890 let read_colors = |reader: &mut BitReader<'_>| -> Option<ColorComponents> {
891 helpers.read_colors(reader, has_function, decode)
892 };
893
894 let mut prev_patch_points: Option<Vec<Point>> = None;
895 let mut prev_patch_colors: Option<[ColorComponents; 4]> = None;
896 let mut patches = vec![];
897
898 while let Some(flag) = reader.read(bpf) {
899 let mut control_points = vec![Point::ZERO; 16]; let mut colors = [smallvec![], smallvec![], smallvec![], smallvec![]];
901
902 match flag {
903 0 => {
904 for i in 0..control_points_count {
905 control_points[i] = helpers.read_point(&mut reader)?;
906 }
907
908 for i in 0..4 {
909 colors[i] = read_colors(&mut reader)?;
910 }
911
912 prev_patch_points = Some(control_points.clone());
913 prev_patch_colors = Some(colors.clone());
914 }
915 1..=3 => {
916 let prev_points = prev_patch_points.as_ref()?;
917 let prev_colors = prev_patch_colors.as_ref()?;
918
919 copy_patch_control_points(flag, prev_points, &mut control_points);
920
921 match flag {
922 1 => {
923 colors[0] = prev_colors[1].clone();
924 colors[1] = prev_colors[2].clone();
925 }
926 2 => {
927 colors[0] = prev_colors[2].clone();
928 colors[1] = prev_colors[3].clone();
929 }
930 3 => {
931 colors[0] = prev_colors[3].clone();
932 colors[1] = prev_colors[0].clone();
933 }
934 _ => unreachable!(),
935 }
936
937 for i in 4..control_points_count {
938 control_points[i] = helpers.read_point(&mut reader)?;
939 }
940
941 colors[2] = read_colors(&mut reader)?;
942 colors[3] = read_colors(&mut reader)?;
943
944 prev_patch_points = Some(control_points.clone());
945 prev_patch_colors = Some(colors.clone());
946 }
947 _ => break,
948 }
949
950 let mut fixed_points = [Point::ZERO; 16];
951 for i in 0..16 {
952 if i < control_points.len() {
953 fixed_points[i] = control_points[i];
954 }
955 }
956
957 patches.push(create_patch(fixed_points, colors));
958 }
959 Some(patches)
960}
961
962fn copy_patch_control_points(
963 flag: u32,
964 prev_control_points: &[Point],
965 control_points: &mut [Point],
966) {
967 match flag {
968 1 => {
969 control_points[0] = prev_control_points[3];
970 control_points[1] = prev_control_points[4];
971 control_points[2] = prev_control_points[5];
972 control_points[3] = prev_control_points[6];
973 }
974 2 => {
975 control_points[0] = prev_control_points[6];
976 control_points[1] = prev_control_points[7];
977 control_points[2] = prev_control_points[8];
978 control_points[3] = prev_control_points[9];
979 }
980 3 => {
981 control_points[0] = prev_control_points[9];
982 control_points[1] = prev_control_points[10];
983 control_points[2] = prev_control_points[11];
984 control_points[3] = prev_control_points[0];
985 }
986 _ => {}
987 }
988}
989
990fn read_tensor_product_patch_mesh(
991 data: &[u8],
992 bpf: u8,
993 bp_coord: u8,
994 bp_comp: u8,
995 has_function: bool,
996 decode: &[f32],
997) -> Option<Vec<TensorProductPatch>> {
998 read_patch_mesh(
999 data,
1000 bpf,
1001 bp_coord,
1002 bp_comp,
1003 has_function,
1004 decode,
1005 16,
1006 |control_points, colors| TensorProductPatch {
1007 control_points,
1008 colors,
1009 },
1010 )
1011}
1012
1013fn read_function(dict: &Dict<'_>, color_space: &ColorSpace) -> Option<ShadingFunction> {
1014 if let Some(arr) = dict.get::<Array<'_>>(FUNCTION) {
1015 let arr: Option<SmallVec<_>> = arr
1016 .iter::<Object<'_>>()
1017 .map(|o| Function::new(&o))
1018 .collect();
1019 let arr = arr?;
1020
1021 if arr.len() != color_space.num_components() as usize {
1022 warn!("function array of shading has wrong size");
1023
1024 return None;
1025 }
1026
1027 Some(ShadingFunction::Multiple(arr))
1028 } else if let Some(obj) = dict.get::<Object<'_>>(FUNCTION) {
1029 Some(ShadingFunction::Single(Function::new(&obj)?))
1030 } else {
1031 None
1032 }
1033}