@@ -9,7 +9,7 @@ use std::io::{self, BufRead, Cursor, Read, Seek, Write};
9
9
use std:: marker:: PhantomData ;
10
10
use std:: mem;
11
11
12
- use tiff:: decoder:: { Decoder , DecodingResult } ;
12
+ use tiff:: decoder:: { Decoder , DecodingResult , ifd :: Value } ;
13
13
use tiff:: tags:: Tag ;
14
14
15
15
use crate :: color:: { ColorType , ExtendedColorType } ;
@@ -21,6 +21,8 @@ use crate::metadata::Orientation;
21
21
use crate :: { utils, ImageDecoder , ImageEncoder , ImageFormat } ;
22
22
23
23
const TAG_XML_PACKET : Tag = Tag :: Unknown ( 700 ) ;
24
+ const TAG_PHOTOSHOP : Tag = Tag :: Unknown ( 34377 ) ;
25
+ const TAG_RICHTIFF_IPTC : Tag = Tag :: Unknown ( 33723 ) ;
24
26
25
27
/// Decoder for TIFF images.
26
28
pub struct TiffDecoder < R >
@@ -284,6 +286,30 @@ impl<R: BufRead + Seek> ImageDecoder for TiffDecoder<R> {
284
286
. map_err ( ImageError :: from_tiff_decode)
285
287
}
286
288
289
+ fn iptc_metadata ( & mut self ) -> ImageResult < Option < Vec < u8 > > > {
290
+ let Some ( decoder) = & mut self . inner else {
291
+ return Ok ( None ) ;
292
+ } ;
293
+
294
+ if let Ok ( value) = decoder. get_tag ( TAG_PHOTOSHOP ) {
295
+ let mut result = Vec :: new ( ) ;
296
+ value_to_bytes ( value, & mut result) ?;
297
+ return Ok ( Some ( result) ) ;
298
+ }
299
+
300
+ let value = match decoder. get_tag ( TAG_RICHTIFF_IPTC ) {
301
+ Ok ( value) => value,
302
+ Err ( tiff:: TiffError :: FormatError ( tiff:: TiffFormatError :: RequiredTagNotFound ( _) ) ) => {
303
+ return Ok ( None ) ;
304
+ }
305
+ Err ( err) => return Err ( ImageError :: from_tiff_decode ( err) ) ,
306
+ } ;
307
+
308
+ let mut result = Vec :: new ( ) ;
309
+ value_to_bytes ( value, & mut result) ?;
310
+ Ok ( Some ( result) )
311
+ }
312
+
287
313
fn orientation ( & mut self ) -> ImageResult < Orientation > {
288
314
if let Some ( decoder) = & mut self . inner {
289
315
Ok ( decoder
@@ -510,3 +536,42 @@ impl<W: Write + Seek> ImageEncoder for TiffEncoder<W> {
510
536
self . encode ( buf, width, height, color_type)
511
537
}
512
538
}
539
+
540
+ /// This method converts a `Value` to a vector of bytes. A `Value` in Tiff can have different
541
+ /// types, e.g. a byte, a short or a float. This method intents to convert all these types to
542
+ /// a vector of bytes (e.g. a u32 can be represented as a [u8; 4]). However, since this is only
543
+ /// intended to parse values stored in XMP, IPTC and EXIF metadata sections, we ignore / return
544
+ /// an error on a few Values that don't make sense in this context (e.g. Value::Ifd).
545
+ fn value_to_bytes ( value : Value , bytes : & mut Vec < u8 > ) -> ImageResult < ( ) > {
546
+ match value {
547
+ Value :: Byte ( byte) => bytes. push ( byte) ,
548
+ Value :: SignedByte ( sbyte) => bytes. push ( sbyte as u8 ) ,
549
+ Value :: Short ( short) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 2 ] > ( short) ) ,
550
+ Value :: SignedShort ( sshort) => {
551
+ bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 2 ] > ( sshort) )
552
+ }
553
+ Value :: Signed ( signed) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 4 ] > ( signed) ) ,
554
+ Value :: SignedBig ( big) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 8 ] > ( big) ) ,
555
+ Value :: Unsigned ( unsigned) => {
556
+ bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 4 ] > ( unsigned) )
557
+ }
558
+ Value :: UnsignedBig ( big) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 8 ] > ( big) ) ,
559
+ Value :: Float ( float) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 4 ] > ( float) ) ,
560
+ Value :: Double ( double) => bytes. extend_from_slice ( & bytemuck:: cast :: < _ , [ u8 ; 8 ] > ( double) ) ,
561
+ Value :: List ( values) => {
562
+ for value in values {
563
+ value_to_bytes ( value, bytes) ?;
564
+ }
565
+ }
566
+ Value :: Ascii ( str) => bytes. extend_from_slice ( str. as_bytes ( ) ) ,
567
+ _ => {
568
+ return Err ( ImageError :: Unsupported (
569
+ UnsupportedError :: from_format_and_kind (
570
+ ImageFormat :: Tiff . into ( ) ,
571
+ UnsupportedErrorKind :: GenericFeature ( "unable to process metadata" . to_owned ( ) ) ,
572
+ ) ,
573
+ ) )
574
+ }
575
+ }
576
+ Ok ( ( ) )
577
+ }
0 commit comments