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