@@ -994,24 +994,40 @@ impl AvifContext {
994
994
}
995
995
996
996
pub fn nclx_colour_information_ptr ( & self ) -> Result < * const NclxColourInformation > {
997
- match self
997
+ let nclx_colr_boxes = self
998
998
. item_properties
999
- . get ( self . primary_item . id , BoxType :: ColourInformationBox ) ?
1000
- {
1001
- Some ( ItemProperty :: Colour ( ColourInformation :: Nclx ( nclx) ) ) => Ok ( nclx) ,
1002
- None | Some ( ItemProperty :: Colour ( ColourInformation :: Icc ( _) ) ) => Ok ( std:: ptr:: null ( ) ) ,
1003
- Some ( other_property) => panic ! ( "property key mismatch: {:?}" , other_property) ,
999
+ . get_multiple ( self . primary_item . id , |prop| {
1000
+ matches ! ( prop, ItemProperty :: Colour ( ColourInformation :: Nclx ( _) ) )
1001
+ } ) ?;
1002
+
1003
+ match * nclx_colr_boxes. as_slice ( ) {
1004
+ [ ] => Ok ( std:: ptr:: null ( ) ) ,
1005
+ [ ItemProperty :: Colour ( ColourInformation :: Nclx ( nclx) ) , ..] => {
1006
+ if nclx_colr_boxes. len ( ) > 1 {
1007
+ warn ! ( "Multiple nclx colr boxes, using first" ) ;
1008
+ }
1009
+ Ok ( nclx)
1010
+ }
1011
+ _ => unreachable ! ( "Expect only ColourInformation::Nclx(_) matches" ) ,
1004
1012
}
1005
1013
}
1006
1014
1007
1015
pub fn icc_colour_information ( & self ) -> Result < & [ u8 ] > {
1008
- match self
1016
+ let icc_colr_boxes = self
1009
1017
. item_properties
1010
- . get ( self . primary_item . id , BoxType :: ColourInformationBox ) ?
1011
- {
1012
- Some ( ItemProperty :: Colour ( ColourInformation :: Icc ( icc) ) ) => Ok ( icc. bytes . as_slice ( ) ) ,
1013
- None | Some ( ItemProperty :: Colour ( ColourInformation :: Nclx ( _) ) ) => Ok ( & [ ] ) ,
1014
- Some ( other_property) => panic ! ( "property key mismatch: {:?}" , other_property) ,
1018
+ . get_multiple ( self . primary_item . id , |prop| {
1019
+ matches ! ( prop, ItemProperty :: Colour ( ColourInformation :: Icc ( _, _) ) )
1020
+ } ) ?;
1021
+
1022
+ match * icc_colr_boxes. as_slice ( ) {
1023
+ [ ] => Ok ( & [ ] ) ,
1024
+ [ ItemProperty :: Colour ( ColourInformation :: Icc ( icc, _) ) , ..] => {
1025
+ if icc_colr_boxes. len ( ) > 1 {
1026
+ warn ! ( "Multiple ICC profiles in colr boxes, using first" ) ;
1027
+ }
1028
+ Ok ( icc. bytes . as_slice ( ) )
1029
+ }
1030
+ _ => unreachable ! ( "Expect only ColourInformation::Icc(_) matches" ) ,
1015
1031
}
1016
1032
}
1017
1033
@@ -2140,6 +2156,11 @@ fn read_iref<T: Read>(src: &mut BMFFBox<T>) -> Result<TryVec<SingleItemTypeRefer
2140
2156
///
2141
2157
/// Note: HEIF (ISO 23008-12:2017) § 9.3.1 also defines the `iprp` box and
2142
2158
/// related types, but lacks additional requirements specified in 14496-12:2020.
2159
+ ///
2160
+ /// Note: Currently HEIF (ISO 23008-12:2017) § 6.5.5.1 specifies "At most one"
2161
+ /// `colr` box per item, but this is being amended in [DIS 23008-12](https://www.iso.org/standard/83650.html).
2162
+ /// The new text is likely to be "At most one for a given value of `colour_type`",
2163
+ /// so this implementation adheres to that language for forward compatibility.
2143
2164
fn read_iprp < T : Read > (
2144
2165
src : & mut BMFFBox < T > ,
2145
2166
brand : FourCC ,
@@ -2211,6 +2232,9 @@ fn read_iprp<T: Read>(
2211
2232
BoxType :: ImageMirror ,
2212
2233
] ;
2213
2234
let mut prev_transform_index = None ;
2235
+ // Realistically, there should only ever be 1 nclx and 1 icc
2236
+ let mut colour_type_indexes: TryHashMap < FourCC , PropertyIndex > =
2237
+ TryHashMap :: with_capacity ( 2 ) ?;
2214
2238
2215
2239
for a in & association_entry. associations {
2216
2240
if a. property_index == PropertyIndex ( 0 ) {
@@ -2244,6 +2268,28 @@ fn read_iprp<T: Read>(
2244
2268
) ?;
2245
2269
}
2246
2270
}
2271
+ // XXX this is contrary to the published specification; see doc comment
2272
+ // at the beginning of this function for more details
2273
+ ItemProperty :: Colour ( colr) => {
2274
+ let colour_type = colr. colour_type ( ) ;
2275
+ if let Some ( prev_colr_index) = colour_type_indexes. get ( & colour_type) {
2276
+ warn ! (
2277
+ "Multiple '{}' type colr associations with {:?}: {:?} and {:?}" ,
2278
+ colour_type,
2279
+ association_entry. item_id,
2280
+ a. property_index,
2281
+ prev_colr_index
2282
+ ) ;
2283
+ fail_if (
2284
+ strictness != ParseStrictness :: Permissive ,
2285
+ "Each item shall have at most one property association with a
2286
+ ColourInformationBox (colr) for a given value of colour_type \
2287
+ per HEIF (ISO/IEC DIS 23008-12) § 6.5.5.1",
2288
+ ) ?;
2289
+ } else {
2290
+ colour_type_indexes. insert ( colour_type, a. property_index ) ?;
2291
+ }
2292
+ }
2247
2293
_ => { }
2248
2294
}
2249
2295
@@ -2378,7 +2424,10 @@ impl ItemPropertiesBox {
2378
2424
}
2379
2425
2380
2426
fn get ( & self , item_id : ItemId , property_type : BoxType ) -> Result < Option < & ItemProperty > > {
2381
- match self . get_multiple ( item_id, property_type) ?. as_slice ( ) {
2427
+ match self
2428
+ . get_multiple ( item_id, |prop| prop. box_type ( ) == property_type) ?
2429
+ . as_slice ( )
2430
+ {
2382
2431
& [ ] => Ok ( None ) ,
2383
2432
& [ single_value] => Ok ( Some ( single_value) ) ,
2384
2433
multiple_values => {
@@ -2395,17 +2444,15 @@ impl ItemPropertiesBox {
2395
2444
fn get_multiple (
2396
2445
& self ,
2397
2446
item_id : ItemId ,
2398
- property_type : BoxType ,
2447
+ filter : impl Fn ( & ItemProperty ) -> bool ,
2399
2448
) -> Result < TryVec < & ItemProperty > > {
2400
2449
let mut values = TryVec :: new ( ) ;
2401
2450
for entry in & self . association_entries {
2402
2451
for a in & entry. associations {
2403
2452
if entry. item_id == item_id {
2404
2453
match self . properties . get ( & a. property_index ) {
2405
2454
Some ( ItemProperty :: Unsupported ( _) ) => { }
2406
- Some ( property) if property. box_type ( ) == property_type => {
2407
- values. push ( property) ?
2408
- }
2455
+ Some ( property) if filter ( property) => values. push ( property) ?,
2409
2456
_ => { }
2410
2457
}
2411
2458
}
@@ -2809,7 +2856,16 @@ impl fmt::Debug for IccColourInformation {
2809
2856
#[ derive( Debug ) ]
2810
2857
pub enum ColourInformation {
2811
2858
Nclx ( NclxColourInformation ) ,
2812
- Icc ( IccColourInformation ) ,
2859
+ Icc ( IccColourInformation , FourCC ) ,
2860
+ }
2861
+
2862
+ impl ColourInformation {
2863
+ fn colour_type ( & self ) -> FourCC {
2864
+ match self {
2865
+ Self :: Nclx ( _) => FourCC :: from ( * b"nclx" ) ,
2866
+ Self :: Icc ( _, colour_type) => colour_type. clone ( ) ,
2867
+ }
2868
+ }
2813
2869
}
2814
2870
2815
2871
/// Parse colour information
@@ -2853,9 +2909,12 @@ fn read_colr<T: Read>(
2853
2909
full_range_flag,
2854
2910
} ) )
2855
2911
}
2856
- b"rICC" | b"prof" => Ok ( ColourInformation :: Icc ( IccColourInformation {
2857
- bytes : src. read_into_try_vec ( ) ?,
2858
- } ) ) ,
2912
+ b"rICC" | b"prof" => Ok ( ColourInformation :: Icc (
2913
+ IccColourInformation {
2914
+ bytes : src. read_into_try_vec ( ) ?,
2915
+ } ,
2916
+ FourCC :: from ( colour_type) ,
2917
+ ) ) ,
2859
2918
_ => {
2860
2919
error ! ( "read_colr colour_type: {:?}" , colour_type) ;
2861
2920
Err ( Error :: InvalidData (
0 commit comments