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::{FloatExt, PointExt};
10use hayro_syntax::bit_reader::{BitReader, BitSize};
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 ShadingFunction::Single(s) => s.eval(input.clone()),
39 ShadingFunction::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.get::<Array>(DECODE)?.iter::<f32>().collect::<Vec<_>>();
186
187 let triangles = read_free_form_triangles(
188 stream_data.as_ref(),
189 bpf,
190 bp_coord,
191 bp_comp,
192 function.is_some(),
193 &decode,
194 )?;
195
196 ShadingType::TriangleMesh {
197 triangles,
198 function,
199 }
200 }
201 5 => {
202 let stream = stream?;
203 let stream_data = stream.decoded().ok()?;
204 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
205 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
206 let function = read_function(dict, &color_space);
207 let decode = dict.get::<Array>(DECODE)?.iter::<f32>().collect::<Vec<_>>();
208 let vertices_per_row = dict.get::<u32>(VERTICES_PER_ROW)?;
209
210 let triangles = read_lattice_triangles(
211 stream_data.as_ref(),
212 bp_coord,
213 bp_comp,
214 function.is_some(),
215 vertices_per_row,
216 &decode,
217 )?;
218
219 ShadingType::TriangleMesh {
220 triangles,
221 function,
222 }
223 }
224 6 => {
225 let stream = stream?;
226 let stream_data = stream.decoded().ok()?;
227 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
228 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
229 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
230 let function = read_function(dict, &color_space);
231 let decode = dict.get::<Array>(DECODE)?.iter::<f32>().collect::<Vec<_>>();
232
233 let patches = read_coons_patch_mesh(
234 stream_data.as_ref(),
235 bpf,
236 bp_coord,
237 bp_comp,
238 function.is_some(),
239 &decode,
240 )?;
241
242 ShadingType::CoonsPatchMesh { patches, function }
243 }
244 7 => {
245 let stream = stream?;
246 let stream_data = stream.decoded().ok()?;
247 let bp_coord = dict.get::<u8>(BITS_PER_COORDINATE)?;
248 let bp_comp = dict.get::<u8>(BITS_PER_COMPONENT)?;
249 let bpf = dict.get::<u8>(BITS_PER_FLAG)?;
250 let function = read_function(dict, &color_space);
251 let decode = dict.get::<Array>(DECODE)?.iter::<f32>().collect::<Vec<_>>();
252
253 let patches = read_tensor_product_patch_mesh(
254 stream_data.as_ref(),
255 bpf,
256 bp_coord,
257 bp_comp,
258 function.is_some(),
259 &decode,
260 )?;
261
262 ShadingType::TensorProductPatchMesh { patches, function }
263 }
264 _ => return None,
265 };
266
267 let bbox = dict.get::<Rect>(BBOX);
268 let background = dict
269 .get::<Array>(BACKGROUND)
270 .map(|a| a.iter::<f32>().collect::<SmallVec<_>>());
271
272 Some(Self {
273 cache_key,
274 shading_type: Arc::new(shading_type),
275 color_space,
276 clip_path: bbox.map(|r| r.to_path(0.1)),
277 background,
278 })
279 }
280}
281
282impl CacheKey for Shading {
283 fn cache_key(&self) -> u128 {
284 self.cache_key
285 }
286}
287
288#[derive(Clone, Debug)]
290pub struct Triangle {
291 pub p0: TriangleVertex,
293 pub p1: TriangleVertex,
295 pub p2: TriangleVertex,
297 kurbo_tri: kurbo::Triangle,
298 d00: f64,
299 d01: f64,
300 d11: f64,
301}
302
303impl Triangle {
304 pub fn new(p0: TriangleVertex, p1: TriangleVertex, p2: TriangleVertex) -> Self {
306 let v0 = p1.point - p0.point;
307 let v1 = p2.point - p0.point;
308
309 let d00 = v0.dot(v0);
310 let d01 = v0.dot(v1);
311 let d11 = v1.dot(v1);
312
313 let kurbo_tri = kurbo::Triangle::new(p0.point, p1.point, p2.point);
314
315 Self {
316 p0,
317 p1,
318 kurbo_tri,
319 p2,
320 d00,
321 d01,
322 d11,
323 }
324 }
325
326 pub fn interpolate(&self, pos: Point) -> ColorComponents {
330 let (u, v, w) = self.barycentric_coords(pos);
331
332 let mut result = smallvec![];
333
334 for i in 0..self.p0.colors.len() {
335 let c0 = self.p0.colors[i];
336 let c1 = self.p1.colors[i];
337 let c2 = self.p2.colors[i];
338 result.push(u * c0 + v * c1 + w * c2);
339 }
340
341 result
342 }
343
344 pub fn contains_point(&self, pos: Point) -> bool {
346 self.kurbo_tri.winding(pos) != 0
347 }
348
349 pub fn bounding_box(&self) -> kurbo::Rect {
351 self.kurbo_tri.bounding_box()
352 }
353
354 fn barycentric_coords(&self, p: Point) -> (f32, f32, f32) {
355 let (a, b, c) = (self.p0.point, self.p1.point, self.p2.point);
356 let v0 = b - a;
357 let v1 = c - a;
358 let v2 = p - a;
359
360 let d00 = self.d00;
361 let d01 = self.d01;
362 let d11 = self.d11;
363 let d20 = v2.dot(v0);
364 let d21 = v2.dot(v1);
365
366 let denom = d00 * d11 - d01 * d01;
367 let v = (d11 * d20 - d01 * d21) / denom;
368 let w = (d00 * d21 - d01 * d20) / denom;
369 let u = (1.0 - v - w) as f32;
370
371 (u, v as f32, w as f32)
372 }
373}
374
375#[derive(Clone, Debug)]
377pub struct TriangleVertex {
378 flag: u32,
379 pub point: Point,
381 pub colors: ColorComponents,
383}
384
385#[derive(Clone, Debug)]
387pub struct CoonsPatch {
388 pub control_points: [Point; 12],
390 pub colors: [ColorComponents; 4],
392}
393
394#[derive(Clone, Debug)]
396pub struct TensorProductPatch {
397 pub control_points: [Point; 16],
399 pub colors: [ColorComponents; 4],
401}
402
403impl CoonsPatch {
404 pub fn map_coordinate(&self, p: Point) -> Point {
406 let (u, v) = (p.x, p.y);
407
408 let cp = &self.control_points;
409
410 let c1 = CubicBez::new(cp[0], cp[11], cp[10], cp[9]);
411 let c2 = CubicBez::new(cp[3], cp[4], cp[5], cp[6]);
412 let d1 = CubicBez::new(cp[0], cp[1], cp[2], cp[3]);
413 let d2 = CubicBez::new(cp[9], cp[8], cp[7], cp[6]);
414
415 let sc = (1.0 - v) * c1.eval(u).to_vec2() + v * c2.eval(u).to_vec2();
416 let sd = (1.0 - u) * d1.eval(v).to_vec2() + u * d2.eval(v).to_vec2();
417 let sb = (1.0 - v) * ((1.0 - u) * c1.eval(0.0).to_vec2() + u * c1.eval(1.0).to_vec2())
418 + v * ((1.0 - u) * c2.eval(0.0).to_vec2() + u * c2.eval(1.0).to_vec2());
419
420 (sc + sd - sb).to_point()
421 }
422
423 pub fn to_triangles(&self) -> Vec<Triangle> {
425 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p))
426 }
427
428 pub fn interpolate(&self, pos: Point) -> ColorComponents {
430 let (u, v) = (pos.x, pos.y);
431 let (c0, c1, c2, c3) = {
432 (
433 &self.colors[0],
434 &self.colors[1],
435 &self.colors[2],
436 &self.colors[3],
437 )
438 };
439
440 let mut result = SmallVec::new();
441 for i in 0..c0.len() {
442 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
443 + u * (1.0 - v) * c3[i] as f64
444 + u * v * c2[i] as f64
445 + (1.0 - u) * v * c1[i] as f64;
446 result.push(val as f32);
447 }
448
449 result
450 }
451}
452
453impl TensorProductPatch {
454 fn bernstein(i: usize, t: f64) -> f64 {
456 match i {
457 0 => (1.0 - t).powi(3),
458 1 => 3.0 * t * (1.0 - t).powi(2),
459 2 => 3.0 * t.powi(2) * (1.0 - t),
460 3 => t.powi(3),
461 _ => 0.0,
462 }
463 }
464
465 pub fn map_coordinate(&self, p: Point) -> Point {
467 let (u, v) = (p.x, p.y);
468
469 let mut x = 0.0;
470 let mut y = 0.0;
471
472 fn idx(i: usize, j: usize) -> usize {
473 match (i, j) {
474 (0, 0) => 0,
475 (0, 1) => 1,
476 (0, 2) => 2,
477 (0, 3) => 3,
478 (1, 0) => 11,
479 (1, 1) => 12,
480 (1, 2) => 13,
481 (1, 3) => 4,
482 (2, 0) => 10,
483 (2, 1) => 15,
484 (2, 2) => 14,
485 (2, 3) => 5,
486 (3, 0) => 9,
487 (3, 1) => 8,
488 (3, 2) => 7,
489 (3, 3) => 6,
490 _ => panic!("Invalid index"),
491 }
492 }
493
494 for i in 0..4 {
495 for j in 0..4 {
496 let control_point_idx = idx(i, j);
497 let basis = Self::bernstein(i, u) * Self::bernstein(j, v);
498
499 x += self.control_points[control_point_idx].x * basis;
500 y += self.control_points[control_point_idx].y * basis;
501 }
502 }
503
504 Point::new(x, y)
505 }
506
507 pub fn to_triangles(&self) -> Vec<Triangle> {
509 generate_patch_triangles(|p| self.map_coordinate(p), |p| self.interpolate(p))
510 }
511
512 pub fn interpolate(&self, pos: Point) -> ColorComponents {
514 let (u, v) = (pos.x, pos.y);
515 let (c0, c1, c2, c3) = {
516 (
517 &self.colors[0],
518 &self.colors[1],
519 &self.colors[2],
520 &self.colors[3],
521 )
522 };
523
524 let mut result = SmallVec::new();
525 for i in 0..c0.len() {
526 let val = (1.0 - u) * (1.0 - v) * c0[i] as f64
527 + u * (1.0 - v) * c3[i] as f64
528 + u * v * c2[i] as f64
529 + (1.0 - u) * v * c1[i] as f64;
530 result.push(val as f32);
531 }
532
533 result
534 }
535}
536
537fn read_free_form_triangles(
538 data: &[u8],
539 bpf: u8,
540 bp_cord: u8,
541 bp_comp: u8,
542 has_function: bool,
543 decode: &[f32],
544) -> Option<Vec<Triangle>> {
545 let bpf = BitSize::from_u8(bpf)?;
546 let bp_cord = BitSize::from_u8(bp_cord)?;
547 let bp_comp = BitSize::from_u8(bp_comp)?;
548
549 let mut triangles = vec![];
550
551 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
552 let mut reader = BitReader::new(data);
553 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
554
555 let read_single = |reader: &mut BitReader| -> Option<TriangleVertex> {
556 helpers.read_triangle_vertex(reader, bpf, has_function, decode)
557 };
558
559 let mut a = None;
560 let mut b = None;
561 let mut c = None;
562
563 loop {
564 let Some(first) = read_single(&mut reader) else {
565 break;
566 };
567
568 if first.flag == 0 {
569 let second = read_single(&mut reader)?;
570 let third = read_single(&mut reader)?;
571
572 a = Some(first.clone());
573 b = Some(second.clone());
574 c = Some(third.clone());
575 } else if first.flag == 1 {
576 a = Some(b.clone()?);
577 b = Some(c.clone()?);
578 c = Some(first);
579 } else if first.flag == 2 {
580 b = Some(c.clone()?);
581 c = Some(first);
582 }
583
584 let (p0, p1, p2) = (a.clone()?, b.clone()?, c.clone()?);
585
586 if p0.point.nearly_same(p1.point) || p1.point.nearly_same(p2.point) {
587 continue;
588 }
589
590 triangles.push(Triangle::new(a.clone()?, b.clone()?, c.clone()?));
591 }
592
593 Some(triangles)
594}
595
596struct InterpolationHelpers {
598 bp_coord: BitSize,
599 bp_comp: BitSize,
600 coord_max: f32,
601 comp_max: f32,
602 x_min: f32,
603 x_max: f32,
604 y_min: f32,
605 y_max: f32,
606}
607
608impl InterpolationHelpers {
609 fn new(
610 bp_coord: BitSize,
611 bp_comp: BitSize,
612 x_min: f32,
613 x_max: f32,
614 y_min: f32,
615 y_max: f32,
616 ) -> Self {
617 let coord_max = 2.0f32.powi(bp_coord.bits() as i32) - 1.0;
618 let comp_max = 2.0f32.powi(bp_comp.bits() 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: BitSize,
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) -> 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 let mut triangles = vec![];
719
720 for i in 0..(GRID_SIZE - 1) {
721 for j in 0..(GRID_SIZE - 1) {
722 let p00 = grid[i][j];
723 let p10 = grid[i + 1][j];
724 let p01 = grid[i][j + 1];
725 let p11 = grid[i + 1][j + 1];
726
727 let u0 = i as f64 / (GRID_SIZE - 1) as f64;
729 let u1 = (i + 1) as f64 / (GRID_SIZE - 1) as f64;
730 let v0 = j as f64 / (GRID_SIZE - 1) as f64;
731 let v1 = (j + 1) as f64 / (GRID_SIZE - 1) as f64;
732
733 let v00 = TriangleVertex {
735 flag: 0,
736 point: p00,
737 colors: interpolate(Point::new(u0, v0)),
738 };
739 let v10 = TriangleVertex {
740 flag: 0,
741 point: p10,
742 colors: interpolate(Point::new(u1, v0)),
743 };
744 let v01 = TriangleVertex {
745 flag: 0,
746 point: p01,
747 colors: interpolate(Point::new(u0, v1)),
748 };
749 let v11 = TriangleVertex {
750 flag: 0,
751 point: p11,
752 colors: interpolate(Point::new(u1, v1)),
753 };
754
755 triangles.push(Triangle::new(v00.clone(), v10.clone(), v01.clone()));
756 triangles.push(Triangle::new(v10.clone(), v11.clone(), v01.clone()));
757 }
758 }
759
760 triangles
761}
762
763fn read_lattice_triangles(
764 data: &[u8],
765 bp_cord: u8,
766 bp_comp: u8,
767 has_function: bool,
768 vertices_per_row: u32,
769 decode: &[f32],
770) -> Option<Vec<Triangle>> {
771 let bp_cord = BitSize::from_u8(bp_cord)?;
772 let bp_comp = BitSize::from_u8(bp_comp)?;
773
774 let mut lattices = vec![];
775
776 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
777 let mut reader = BitReader::new(data);
778 let helpers = InterpolationHelpers::new(bp_cord, bp_comp, x_min, x_max, y_min, y_max);
779
780 let read_single = |reader: &mut BitReader| -> Option<TriangleVertex> {
781 let point = helpers.read_point(reader)?;
782 let colors = helpers.read_colors(reader, has_function, decode)?;
783 reader.align();
784
785 Some(TriangleVertex {
786 flag: 0,
787 point,
788 colors,
789 })
790 };
791
792 'outer: loop {
793 let mut single_row = vec![];
794
795 for _ in 0..vertices_per_row {
796 let Some(next) = read_single(&mut reader) else {
797 break 'outer;
798 };
799
800 single_row.push(next);
801 }
802
803 lattices.push(single_row);
804 }
805
806 let mut triangles = vec![];
807
808 for i in 0..(lattices.len() - 1) {
809 for j in 0..(vertices_per_row as usize - 1) {
810 triangles.push(Triangle::new(
811 lattices[i][j].clone(),
812 lattices[i + 1][j].clone(),
813 lattices[i][j + 1].clone(),
814 ));
815
816 triangles.push(Triangle::new(
817 lattices[i + 1][j + 1].clone(),
818 lattices[i + 1][j].clone(),
819 lattices[i][j + 1].clone(),
820 ));
821 }
822 }
823
824 Some(triangles)
825}
826
827fn read_coons_patch_mesh(
828 data: &[u8],
829 bpf: u8,
830 bp_coord: u8,
831 bp_comp: u8,
832 has_function: bool,
833 decode: &[f32],
834) -> Option<Vec<CoonsPatch>> {
835 read_patch_mesh(
836 data,
837 bpf,
838 bp_coord,
839 bp_comp,
840 has_function,
841 decode,
842 12,
843 |control_points, colors| {
844 let mut coons_points = [Point::ZERO; 12];
845 coons_points.copy_from_slice(&control_points[0..12]);
846 CoonsPatch {
847 control_points: coons_points,
848 colors,
849 }
850 },
851 )
852}
853
854#[allow(clippy::too_many_arguments)]
856fn read_patch_mesh<P, F>(
857 data: &[u8],
858 bpf: u8,
859 bp_coord: u8,
860 bp_comp: u8,
861 has_function: bool,
862 decode: &[f32],
863 control_points_count: usize,
864 create_patch: F,
865) -> Option<Vec<P>>
866where
867 F: Fn([Point; 16], [ColorComponents; 4]) -> P,
868{
869 let bpf = BitSize::from_u8(bpf)?;
870 let bp_coord = BitSize::from_u8(bp_coord)?;
871 let bp_comp = BitSize::from_u8(bp_comp)?;
872
873 let ([x_min, x_max, y_min, y_max], decode) = split_decode(decode)?;
874 let mut reader = BitReader::new(data);
875 let helpers = InterpolationHelpers::new(bp_coord, bp_comp, x_min, x_max, y_min, y_max);
876
877 let read_colors = |reader: &mut BitReader| -> Option<ColorComponents> {
878 helpers.read_colors(reader, has_function, decode)
879 };
880
881 let mut prev_patch_points: Option<Vec<Point>> = None;
882 let mut prev_patch_colors: Option<[ColorComponents; 4]> = None;
883 let mut patches = vec![];
884
885 while let Some(flag) = reader.read(bpf) {
886 let mut control_points = vec![Point::ZERO; 16]; let mut colors = [smallvec![], smallvec![], smallvec![], smallvec![]];
888
889 match flag {
890 0 => {
891 for i in 0..control_points_count {
892 control_points[i] = helpers.read_point(&mut reader)?;
893 }
894
895 for i in 0..4 {
896 colors[i] = read_colors(&mut reader)?;
897 }
898
899 prev_patch_points = Some(control_points.clone());
900 prev_patch_colors = Some(colors.clone());
901 }
902 1..=3 => {
903 let prev_points = prev_patch_points.as_ref()?;
904 let prev_colors = prev_patch_colors.as_ref()?;
905
906 copy_patch_control_points(flag, prev_points, &mut control_points);
907
908 match flag {
909 1 => {
910 colors[0] = prev_colors[1].clone();
911 colors[1] = prev_colors[2].clone();
912 }
913 2 => {
914 colors[0] = prev_colors[2].clone();
915 colors[1] = prev_colors[3].clone();
916 }
917 3 => {
918 colors[0] = prev_colors[3].clone();
919 colors[1] = prev_colors[0].clone();
920 }
921 _ => unreachable!(),
922 }
923
924 for i in 4..control_points_count {
925 control_points[i] = helpers.read_point(&mut reader)?;
926 }
927
928 colors[2] = read_colors(&mut reader)?;
929 colors[3] = read_colors(&mut reader)?;
930
931 prev_patch_points = Some(control_points.clone());
932 prev_patch_colors = Some(colors.clone());
933 }
934 _ => break,
935 }
936
937 let mut fixed_points = [Point::ZERO; 16];
938 for i in 0..16 {
939 if i < control_points.len() {
940 fixed_points[i] = control_points[i];
941 }
942 }
943
944 patches.push(create_patch(fixed_points, colors));
945 }
946 Some(patches)
947}
948
949fn copy_patch_control_points(
950 flag: u32,
951 prev_control_points: &[Point],
952 control_points: &mut [Point],
953) {
954 match flag {
955 1 => {
956 control_points[0] = prev_control_points[3];
957 control_points[1] = prev_control_points[4];
958 control_points[2] = prev_control_points[5];
959 control_points[3] = prev_control_points[6];
960 }
961 2 => {
962 control_points[0] = prev_control_points[6];
963 control_points[1] = prev_control_points[7];
964 control_points[2] = prev_control_points[8];
965 control_points[3] = prev_control_points[9];
966 }
967 3 => {
968 control_points[0] = prev_control_points[9];
969 control_points[1] = prev_control_points[10];
970 control_points[2] = prev_control_points[11];
971 control_points[3] = prev_control_points[0];
972 }
973 _ => {}
974 }
975}
976
977fn read_tensor_product_patch_mesh(
978 data: &[u8],
979 bpf: u8,
980 bp_coord: u8,
981 bp_comp: u8,
982 has_function: bool,
983 decode: &[f32],
984) -> Option<Vec<TensorProductPatch>> {
985 read_patch_mesh(
986 data,
987 bpf,
988 bp_coord,
989 bp_comp,
990 has_function,
991 decode,
992 16,
993 |control_points, colors| TensorProductPatch {
994 control_points,
995 colors,
996 },
997 )
998}
999
1000fn read_function(dict: &Dict, color_space: &ColorSpace) -> Option<ShadingFunction> {
1001 if let Some(arr) = dict.get::<Array>(FUNCTION) {
1002 let arr: Option<SmallVec<_>> = arr.iter::<Object>().map(|o| Function::new(&o)).collect();
1003 let arr = arr?;
1004
1005 if arr.len() != color_space.num_components() as usize {
1006 warn!("function array of shading has wrong size");
1007
1008 return None;
1009 }
1010
1011 Some(ShadingFunction::Multiple(arr))
1012 } else if let Some(obj) = dict.get::<Object>(FUNCTION) {
1013 Some(ShadingFunction::Single(Function::new(&obj)?))
1014 } else {
1015 None
1016 }
1017}