@@ -7,11 +7,7 @@ use pdf_graphics::{color::Color, point::Point};
77use pdf_utils:: BitReader ;
88use thiserror:: Error ;
99
10- use crate :: error:: PdfShadingError ;
11-
12- const VALID_COORDINATE_WIDTHS : [ usize ; 8 ] = [ 1 , 2 , 4 , 8 , 12 , 16 , 24 , 32 ] ;
13- const VALID_COMPONENT_WIDTHS : [ usize ; 6 ] = [ 1 , 2 , 4 , 8 , 12 , 16 ] ;
14- const VALID_FLAG_WIDTHS : [ usize ; 3 ] = [ 2 , 4 , 8 ] ;
10+ use crate :: { error:: PdfShadingError , mesh_bit_widths:: MeshBitWidths } ;
1511
1612/// Errors produced while validating and decoding packed mesh samples.
1713#[ derive( Debug , Error , Clone , PartialEq , Eq ) ]
@@ -61,50 +57,6 @@ pub enum MeshDecoderError {
6157 SampleRangeNotRepresentable ,
6258}
6359
64- /// Validated bit widths from a Type 4, 6, or 7 mesh dictionary.
65- #[ derive( Debug , Clone , Copy ) ]
66- pub ( crate ) struct MeshBitWidths {
67- coordinate : usize ,
68- component : usize ,
69- flag : usize ,
70- }
71-
72- impl MeshBitWidths {
73- /// Validates the three PDF mesh bit-width entries.
74- pub ( crate ) fn new (
75- coordinate : usize ,
76- component : usize ,
77- flag : usize ,
78- ) -> Result < Self , PdfShadingError > {
79- validate_allowed_width (
80- coordinate,
81- & VALID_COORDINATE_WIDTHS ,
82- MeshDecoderError :: InvalidBitsPerCoordinate { value : coordinate } ,
83- ) ?;
84- validate_allowed_width (
85- component,
86- & VALID_COMPONENT_WIDTHS ,
87- MeshDecoderError :: InvalidBitsPerComponent { value : component } ,
88- ) ?;
89- validate_allowed_width (
90- flag,
91- & VALID_FLAG_WIDTHS ,
92- MeshDecoderError :: InvalidBitsPerFlag { value : flag } ,
93- ) ?;
94-
95- Ok ( Self {
96- coordinate,
97- component,
98- flag,
99- } )
100- }
101-
102- /// Returns the width of each edge-flag field.
103- pub ( crate ) fn flag ( self ) -> usize {
104- self . flag
105- }
106- }
107-
10860/// Decodes mesh coordinates and color inputs according to a `/Decode` array.
10961///
11062/// A decoder borrows the parsed dictionary data while a mesh parser owns the
@@ -159,8 +111,8 @@ impl<'a> MeshDecoder<'a> {
159111 pub ( crate ) fn read_point ( & self , reader : & mut BitReader < ' _ > ) -> Result < Point , PdfShadingError > {
160112 let ( x_min, x_max) = decode_pair ( self . decode , 0 , "X" ) ?;
161113 let ( y_min, y_max) = decode_pair ( self . decode , 1 , "Y" ) ?;
162- let x = self . read_sample ( reader, self . widths . coordinate , x_min, x_max) ?;
163- let y = self . read_sample ( reader, self . widths . coordinate , y_min, y_max) ?;
114+ let x = self . read_sample ( reader, self . widths . coordinate ( ) , x_min, x_max) ?;
115+ let y = self . read_sample ( reader, self . widths . coordinate ( ) , y_min, y_max) ?;
164116 Ok ( Point :: new ( x, y) )
165117 }
166118
@@ -171,27 +123,43 @@ impl<'a> MeshDecoder<'a> {
171123 . map ( |component| {
172124 let ( min, max) =
173125 decode_pair ( self . decode , component. saturating_add ( 2 ) , "component" ) ?;
174- self . read_sample ( reader, self . widths . component , min, max)
126+ self . read_sample ( reader, self . widths . component ( ) , min, max)
175127 } )
176128 . collect :: < Result < Vec < _ > , PdfShadingError > > ( ) ?;
177129
178130 let components = self . apply_functions ( & inputs) ?;
179131 Ok ( self . color_space . apply ( & components) ?)
180132 }
181133
134+ /// Reads a required packed sample and maps it into the supplied decode range.
135+ ///
136+ /// The encoded integer is scaled linearly from the range representable by
137+ /// `width` bits into `min..=max`. An error is returned when the stream ends
138+ /// before the sample, contains only part of it, uses an unsupported width,
139+ /// or the encoded value or its range cannot be represented as `f32`.
182140 fn read_sample (
183141 & self ,
184142 reader : & mut BitReader < ' _ > ,
185143 width : usize ,
186144 min : f32 ,
187145 max : f32 ,
188146 ) -> Result < f32 , PdfShadingError > {
189- decode_sample (
190- read_required_mesh_bits ( reader, width) ?. into ( ) ,
191- width,
192- min,
193- max,
194- )
147+ let code = read_mesh_bits ( reader, width) ?
148+ . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: UnexpectedEndOfStream ) ) ?;
149+ let shift = u32:: try_from ( width)
150+ . map_err ( |_| PdfShadingError :: from ( MeshDecoderError :: InvalidBitFieldWidth { width } ) ) ?;
151+ let code_max = 1_u64
152+ . checked_shl ( shift)
153+ . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: InvalidBitFieldWidth { width } ) ) ?
154+ . saturating_sub ( 1 ) ;
155+ let code = u64:: from ( code)
156+ . to_f32 ( )
157+ . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: SampleNotRepresentable ) ) ?;
158+ let code_max = code_max
159+ . to_f32 ( )
160+ . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: SampleRangeNotRepresentable ) ) ?;
161+
162+ Ok ( min + ( code / code_max) * ( max - min) )
195163 }
196164
197165 fn apply_functions ( & self , inputs : & [ f32 ] ) -> Result < Vec < f32 > , PdfShadingError > {
@@ -230,27 +198,6 @@ pub(crate) fn read_mesh_bits(
230198 . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: TruncatedSample ) )
231199}
232200
233- /// Reads a mesh field that is required to complete the current record.
234- fn read_required_mesh_bits (
235- reader : & mut BitReader < ' _ > ,
236- width : usize ,
237- ) -> Result < u32 , PdfShadingError > {
238- read_mesh_bits ( reader, width) ?
239- . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: UnexpectedEndOfStream ) )
240- }
241-
242- fn validate_allowed_width (
243- width : usize ,
244- allowed : & [ usize ] ,
245- error : MeshDecoderError ,
246- ) -> Result < ( ) , PdfShadingError > {
247- if allowed. contains ( & width) {
248- Ok ( ( ) )
249- } else {
250- Err ( error. into ( ) )
251- }
252- }
253-
254201fn decode_pair (
255202 decode : & [ f32 ] ,
256203 pair_index : usize ,
@@ -269,23 +216,6 @@ fn decode_pair(
269216 Ok ( ( min, max) )
270217}
271218
272- fn decode_sample ( code : u64 , width : usize , min : f32 , max : f32 ) -> Result < f32 , PdfShadingError > {
273- let shift = u32:: try_from ( width)
274- . map_err ( |_| PdfShadingError :: from ( MeshDecoderError :: InvalidBitFieldWidth { width } ) ) ?;
275- let code_max = 1_u64
276- . checked_shl ( shift)
277- . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: InvalidBitFieldWidth { width } ) ) ?
278- . saturating_sub ( 1 ) ;
279- let code = code
280- . to_f32 ( )
281- . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: SampleNotRepresentable ) ) ?;
282- let code_max = code_max
283- . to_f32 ( )
284- . ok_or_else ( || PdfShadingError :: from ( MeshDecoderError :: SampleRangeNotRepresentable ) ) ?;
285-
286- Ok ( min + ( code / code_max) * ( max - min) )
287- }
288-
289219#[ cfg( test) ]
290220#[ path = "../tests/mesh_decoder.rs" ]
291221mod tests;
0 commit comments