@@ -18,8 +18,9 @@ enum Format {
1818
1919/// A multi-format image reader.
2020///
21- /// Wraps an input reader to facilitate automatic detection of an image's format, appropriate
22- /// decoding method, and dispatches into the set of supported [`ImageDecoder`] implementations.
21+ /// Wraps an input stream to facilitate automatic detection of an image's format, appropriate
22+ /// decoding method, and turn it into an [`ImageDecoder`] implementation. For convenience, it also
23+ /// allows directly decoding into a [`DynamicImage`].
2324///
2425/// ## Usage
2526///
@@ -74,9 +75,21 @@ pub struct ImageFile<R: Read + Seek> {
7475 limits : Limits ,
7576}
7677
78+ /// An abstracted image reader.
79+ ///
80+ /// Wraps an input reader after its format was determined. It provides more detailed decoding
81+ /// methods than [`ImageFile`] and under the hood dispatches into the set of supported
82+ /// [`ImageDecoder`] implementations. For decoder interface that are provided for efficiency it
83+ /// negotiates support with the underlying decoder and then emulates them if necessary.
7784pub struct ImageReader < ' lt > {
7885 /// The reader. Should be buffered.
7986 inner : Box < dyn ImageDecoder + ' lt > ,
87+ /// An additional viewbox to apply after decoding.
88+ ///
89+ /// This is only used if the inner decoder does not support viewboxes directly.
90+ viewbox : Option < crate :: math:: Rect > ,
91+ /// Remaining limits for allocations by the reader.
92+ limits : Limits ,
8093}
8194
8295impl < ' a , R : ' a + BufRead + Seek > ImageFile < R > {
@@ -225,7 +238,11 @@ impl<'a, R: 'a + BufRead + Seek> ImageFile<R> {
225238 let mut decoder = Self :: make_decoder ( format, self . inner ) ?;
226239 decoder. set_limits ( self . limits . clone ( ) ) ?;
227240
228- Ok ( ImageReader { inner : decoder } )
241+ Ok ( ImageReader {
242+ inner : decoder,
243+ viewbox : None ,
244+ limits : self . limits ,
245+ } )
229246 }
230247
231248 /// Make a format guess based on the content, replacing it on success.
@@ -303,22 +320,9 @@ impl<'a, R: 'a + BufRead + Seek> ImageFile<R> {
303320 /// Uses the current format to construct the correct reader for the format.
304321 ///
305322 /// If no format was determined, returns an `ImageError::Unsupported`.
306- pub fn decode ( mut self ) -> ImageResult < DynamicImage > {
307- let format = self . require_format ( ) ?;
308-
309- let mut limits = self . limits ;
310-
311- let mut decoder = Self :: make_decoder ( format, self . inner ) ?;
312- decoder. set_limits ( limits. clone ( ) ) ?;
313- let layout = decoder. next_layout ( ) ?;
314-
315- // This is technically redundant but it's also cheap.
316- limits. check_dimensions ( layout. width , layout. height ) ?;
317- // Check that we do not allocate a bigger buffer than we are allowed to
318- // FIXME: should this rather go in `DynamicImage::from_decoder` somehow?
319- limits. reserve ( layout. total_bytes ( ) ) ?;
320-
321- DynamicImage :: decoder_to_image ( decoder. as_mut ( ) , layout)
323+ pub fn decode ( self ) -> ImageResult < DynamicImage > {
324+ let mut reader = self . into_reader ( ) ?;
325+ reader. decode ( )
322326 }
323327
324328 fn require_format ( & mut self ) -> ImageResult < Format > {
@@ -364,22 +368,73 @@ impl ImageFile<BufReader<File>> {
364368impl ImageReader < ' _ > {
365369 /// Decode the next image into a `DynamicImage`.
366370 pub fn decode ( & mut self ) -> ImageResult < DynamicImage > {
371+ // Try to resolve the viewbox via the decoder, fallback to `crop` if that is not possible.
372+ let residual_vb = self . viewbox . and_then ( |vb| self . inner . viewbox ( vb) . err ( ) ) ;
373+
367374 let layout = self . inner . next_layout ( ) ?;
368- DynamicImage :: decoder_to_image ( self . inner . as_mut ( ) , layout)
375+ // This is technically redundant but it's also cheap.
376+ self . limits . check_dimensions ( layout. width , layout. height ) ?;
377+ // Check that we do not allocate a bigger buffer than we are allowed to
378+ // FIXME: should this rather go in `DynamicImage::from_decoder` somehow?
379+ self . limits . reserve ( layout. total_bytes ( ) ) ?;
380+
381+ let mut image = DynamicImage :: decoder_to_image ( self . inner . as_mut ( ) , layout) ?;
382+
383+ // Apply the profile. If the profile itself is not valid or not present you get the default
384+ // presumption: `sRGB`. Otherwise we will try to make sense of the profile and if it is not
385+ // RGB we'll treat it as unspecified so that downstream will know that our handling of this
386+ // _existing_ profile was not / could not be done with full fidelity.
387+ if let Some ( icc) = self . inner . icc_profile ( ) ? {
388+ if let Some ( cicp) = crate :: metadata:: cms_provider ( ) . parse_icc ( & icc) {
389+ // We largely ignore the error itself here, you just get the image with no color
390+ // space attached to it.
391+ if let Ok ( rgb) = cicp. try_into_rgb ( ) {
392+ image. set_rgb_primaries ( rgb. primaries ) ;
393+ image. set_transfer_function ( rgb. transfer ) ;
394+ } else {
395+ image. set_rgb_primaries ( crate :: metadata:: CicpColorPrimaries :: Unspecified ) ;
396+ image. set_transfer_function (
397+ crate :: metadata:: CicpTransferCharacteristics :: Unspecified ,
398+ ) ;
399+ }
400+ }
401+ }
402+
403+ Ok ( if let Some ( vb) = residual_vb {
404+ // Crop the image. This re-allocates a completely new buffer. For other types it may be
405+ // possible to do so with less work but not the normalized `ImageBuffer`.
406+ image. crop_imm ( vb. x , vb. y , vb. width , vb. height )
407+ } else {
408+ image
409+ } )
410+ }
411+
412+ /// Query the layout that the image will have.
413+ pub fn layout ( & mut self ) -> ImageResult < crate :: ImageLayout > {
414+ self . inner . next_layout ( )
415+ }
416+
417+ /// Set the viewbox to apply when decoding images.
418+ pub fn set_viewbox ( & mut self , viewbox : crate :: math:: Rect ) {
419+ self . viewbox = Some ( viewbox) ;
369420 }
370421
422+ /// Get the previously decoded EXIF metadata if any.
371423 pub fn exif_metadata ( & mut self ) -> ImageResult < Option < Vec < u8 > > > {
372424 self . inner . exif_metadata ( )
373425 }
374426
427+ /// Get the previously decoded ICC profile if any.
375428 pub fn icc_profile ( & mut self ) -> ImageResult < Option < Vec < u8 > > > {
376429 self . inner . icc_profile ( )
377430 }
378431
432+ /// Get the previously decoded XMP metadata if any.
379433 pub fn xmp_metadata ( & mut self ) -> ImageResult < Option < Vec < u8 > > > {
380434 self . inner . xmp_metadata ( )
381435 }
382436
437+ /// Get the previously decoded IPTC metadata if any.
383438 pub fn iptc_metadata ( & mut self ) -> ImageResult < Option < Vec < u8 > > > {
384439 self . inner . iptc_metadata ( )
385440 }
0 commit comments