@@ -75,13 +75,15 @@ pub struct ImageInfo {
75
75
}
76
76
77
77
/// Describes the colour transform to apply before binary data is returned
78
- #[ derive( Debug , Clone , Copy ) ]
78
+ #[ derive( Debug , Clone , Copy , PartialEq , Eq , Hash ) ]
79
79
#[ non_exhaustive]
80
80
pub enum ColorTransform {
81
81
/// No transform should be applied and the data is returned as-is.
82
82
None ,
83
- /// Default colour transform should be applied. If there are 3 channels then YCbCr and if there are 4 then YCCK.
84
- Default ,
83
+ /// Unknown colour transformation
84
+ Unknown ,
85
+ /// Grayscale transform should be applied (expects 1 channel)
86
+ Grayscale ,
85
87
/// RGB transform should be applied.
86
88
RGB ,
87
89
/// YCbCr transform should be applied.
@@ -90,14 +92,10 @@ pub enum ColorTransform {
90
92
CMYK ,
91
93
/// YCCK transform should be applied.
92
94
YCCK ,
93
- /// Use the colour transform specified in the Adobe extended tag
94
- AdobeColorTransform ( AdobeColorTransform ) ,
95
- }
96
-
97
- impl Default for ColorTransform {
98
- fn default ( ) -> Self {
99
- ColorTransform :: Default
100
- }
95
+ /// big gamut Y/Cb/Cr, bg-sYCC
96
+ JcsBgYcc ,
97
+ /// big gamut red/green/blue, bg-sRGB
98
+ JcsBgRgb ,
101
99
}
102
100
103
101
/// JPEG decoder
@@ -110,8 +108,10 @@ pub struct Decoder<R> {
110
108
quantization_tables : [ Option < Arc < [ u16 ; 64 ] > > ; 4 ] ,
111
109
112
110
restart_interval : u16 ,
113
- fallback_color_transform : ColorTransform ,
111
+
112
+ adobe_color_transform : Option < AdobeColorTransform > ,
114
113
color_transform : Option < ColorTransform > ,
114
+
115
115
is_jfif : bool ,
116
116
is_mjpeg : bool ,
117
117
@@ -138,8 +138,7 @@ impl<R: Read> Decoder<R> {
138
138
ac_huffman_tables : vec ! [ None , None , None , None ] ,
139
139
quantization_tables : [ None , None , None , None ] ,
140
140
restart_interval : 0 ,
141
- // Set the fallback transform as unknown. This can be overriden using `set_color_transform`
142
- fallback_color_transform : ColorTransform :: default ( ) ,
141
+ adobe_color_transform : None ,
143
142
color_transform : None ,
144
143
is_jfif : false ,
145
144
is_mjpeg : false ,
@@ -151,11 +150,6 @@ impl<R: Read> Decoder<R> {
151
150
}
152
151
}
153
152
154
- /// Colour transform to use if one is not set using `set_color_transform` or found in app segments.
155
- pub fn set_fallback_color_transform ( & mut self , transform : ColorTransform ) {
156
- self . fallback_color_transform = transform;
157
- }
158
-
159
153
/// Colour transform to use when decoding the image. App segments relating to colour transforms
160
154
/// will be ignored.
161
155
pub fn set_color_transform ( & mut self , transform : ColorTransform ) {
@@ -529,12 +523,7 @@ impl<R: Read> Decoder<R> {
529
523
if let Some ( data) = parse_app ( & mut self . reader , marker) ? {
530
524
match data {
531
525
AppData :: Adobe ( color_transform) => {
532
- // Set the colour transform if it has not already been set by the user
533
- // calling `set_color_transform`
534
- if self . color_transform . is_none ( ) {
535
- self . color_transform =
536
- Some ( ColorTransform :: AdobeColorTransform ( color_transform) )
537
- }
526
+ self . adobe_color_transform = Some ( color_transform)
538
527
}
539
528
AppData :: Jfif => {
540
529
// From the JFIF spec:
@@ -687,21 +676,85 @@ impl<R: Read> Decoder<R> {
687
676
compute_image_lossless ( frame, planes_u16)
688
677
} else {
689
678
// Check whether a colour transform has been set - if not use the fallback
690
- let color_transform = match self . color_transform {
691
- Some ( color_transform) => color_transform,
692
- None => self . fallback_color_transform ,
693
- } ;
679
+ // let color_transform = match self.color_transform {
680
+ // Some(color_transform) => color_transform,
681
+ // None => self.fallback_color_transform,
682
+ // };
694
683
695
684
compute_image (
696
685
& frame. components ,
697
686
planes,
698
687
frame. output_size ,
699
688
self . is_jfif ,
700
- color_transform ,
689
+ self . determine_color_transform ( ) ,
701
690
)
702
691
}
703
692
}
704
693
694
+ fn determine_color_transform ( & self ) -> ColorTransform {
695
+ if let Some ( color_transform) = self . color_transform {
696
+ return color_transform;
697
+ }
698
+
699
+ let frame = self . frame . as_ref ( ) . unwrap ( ) ;
700
+
701
+ if frame. components . len ( ) == 1 {
702
+ return ColorTransform :: Grayscale ;
703
+ }
704
+
705
+ // Using logic for determining colour as described here: https://entropymine.wordpress.com/2018/10/22/how-is-a-jpeg-images-color-type-determined/
706
+
707
+ if frame. components . len ( ) == 3 {
708
+ match (
709
+ frame. components [ 0 ] . identifier ,
710
+ frame. components [ 1 ] . identifier ,
711
+ frame. components [ 2 ] . identifier ,
712
+ ) {
713
+ ( 1 , 2 , 3 ) => {
714
+ return ColorTransform :: YCbCr ;
715
+ }
716
+ ( 1 , 34 , 35 ) => {
717
+ return ColorTransform :: JcsBgYcc ;
718
+ }
719
+ ( 82 , 71 , 66 ) => {
720
+ return ColorTransform :: RGB ;
721
+ }
722
+ ( 114 , 103 , 98 ) => {
723
+ return ColorTransform :: JcsBgRgb ;
724
+ }
725
+ _ => { }
726
+ }
727
+
728
+ if self . is_jfif {
729
+ return ColorTransform :: YCbCr ;
730
+ }
731
+ }
732
+
733
+ if let Some ( colour_transform) = self . adobe_color_transform {
734
+ match colour_transform {
735
+ AdobeColorTransform :: Unknown => {
736
+ if frame. components . len ( ) == 3 {
737
+ return ColorTransform :: RGB ;
738
+ } else if frame. components . len ( ) == 4 {
739
+ return ColorTransform :: CMYK ;
740
+ }
741
+ }
742
+ AdobeColorTransform :: YCbCr => {
743
+ return ColorTransform :: YCbCr ;
744
+ }
745
+ AdobeColorTransform :: YCCK => {
746
+ return ColorTransform :: YCCK ;
747
+ }
748
+ }
749
+ }
750
+
751
+ if frame. components . len ( ) == 4 {
752
+ ColorTransform :: YCCK
753
+ } else {
754
+ ColorTransform :: Unknown
755
+ }
756
+ }
757
+
705
758
fn read_marker ( & mut self ) -> Result < Marker > {
706
759
loop {
707
760
// This should be an error as the JPEG spec doesn't allow extraneous data between marker segments.
@@ -1278,50 +1331,49 @@ pub(crate) fn choose_color_convert_func(
1278
1331
color_transform : ColorTransform ,
1279
1332
) -> Result < fn ( & [ Vec < u8 > ] , & mut [ u8 ] ) > {
1280
1333
match component_count {
1281
- 3 => {
1282
- match color_transform {
1283
- ColorTransform :: None => Ok ( color_no_convert) ,
1284
- ColorTransform :: Default => Ok ( color_convert_line_ycbcr) ,
1285
- ColorTransform :: RGB => Ok ( color_convert_line_rgb) ,
1286
- ColorTransform :: YCbCr => Ok ( color_convert_line_ycbcr) ,
1287
- ColorTransform :: CMYK => Err ( Error :: Format (
1288
- "Invalid number of channels (3) for CMYK data" . to_string ( ) ,
1289
- ) ) ,
1290
- ColorTransform :: YCCK => Err ( Error :: Format (
1291
- "Invalid number of channels (3) for YCCK data" . to_string ( ) ,
1292
- ) ) ,
1293
- ColorTransform :: AdobeColorTransform ( adobe_transform) => {
1294
- // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
1295
- // Unknown means the data is RGB, so we don't need to perform any color conversion on it.
1296
- if adobe_transform == AdobeColorTransform :: Unknown {
1297
- Ok ( color_convert_line_rgb)
1298
- } else {
1299
- Ok ( color_convert_line_ycbcr)
1300
- }
1301
- }
1302
- }
1303
- }
1304
- 4 => {
1305
- match color_transform {
1306
- ColorTransform :: None => Ok ( color_no_convert) ,
1307
- ColorTransform :: Default => Ok ( color_convert_line_cmyk) ,
1308
- ColorTransform :: RGB => Err ( Error :: Format (
1309
- "Invalid number of channels (4) for RGB data" . to_string ( ) ,
1310
- ) ) ,
1311
- ColorTransform :: YCbCr => Err ( Error :: Format (
1312
- "Invalid number of channels (4) for YCbCr data" . to_string ( ) ,
1313
- ) ) ,
1314
- ColorTransform :: CMYK => Ok ( color_convert_line_cmyk) ,
1315
- ColorTransform :: YCCK => Ok ( color_convert_line_ycck) ,
1316
- ColorTransform :: AdobeColorTransform ( adobe_transform) => {
1317
- // http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/JPEG.html#Adobe
1318
- match adobe_transform {
1319
- AdobeColorTransform :: Unknown => Ok ( color_convert_line_cmyk) ,
1320
- _ => Ok ( color_convert_line_ycck) ,
1321
- }
1322
- }
1323
- }
1324
- }
1334
+ 3 => match color_transform {
1335
+ ColorTransform :: None => Ok ( color_no_convert) ,
1336
+ ColorTransform :: RGB => Ok ( color_convert_line_rgb) ,
1337
+ ColorTransform :: YCbCr => Ok ( color_convert_line_ycbcr) ,
1338
+ ColorTransform :: CMYK => Err ( Error :: Format (
1339
+ "Invalid number of channels (3) for CMYK data" . to_string ( ) ,
1340
+ ) ) ,
1341
+ ColorTransform :: YCCK => Err ( Error :: Format (
1342
+ "Invalid number of channels (3) for YCCK data" . to_string ( ) ,
1343
+ ) ) ,
1344
+ ColorTransform :: JcsBgYcc => Err ( Error :: Unsupported (
1345
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: JcsBgYcc ) ,
1346
+ ) ) ,
1347
+ ColorTransform :: JcsBgRgb => Err ( Error :: Unsupported (
1348
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: JcsBgRgb ) ,
1349
+ ) ) ,
1350
+ ColorTransform :: Unknown => Err ( Error :: Format ( "Unknown colour transform" . to_string ( ) ) ) ,
1351
+ ColorTransform :: Grayscale => Err ( Error :: Unsupported (
1352
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: Grayscale ) ,
1353
+ ) ) ,
1354
+ } ,
1355
+ 4 => match color_transform {
1356
+ ColorTransform :: None => Ok ( color_no_convert) ,
1357
+ ColorTransform :: RGB => Err ( Error :: Format (
1358
+ "Invalid number of channels (4) for RGB data" . to_string ( ) ,
1359
+ ) ) ,
1360
+ ColorTransform :: YCbCr => Err ( Error :: Format (
1361
+ "Invalid number of channels (4) for YCbCr data" . to_string ( ) ,
1362
+ ) ) ,
1363
+ ColorTransform :: CMYK => Ok ( color_convert_line_cmyk) ,
1364
+ ColorTransform :: YCCK => Ok ( color_convert_line_ycck) ,
1365
+
1366
+ ColorTransform :: JcsBgYcc => Err ( Error :: Unsupported (
1367
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: JcsBgYcc ) ,
1368
+ ) ) ,
1369
+ ColorTransform :: JcsBgRgb => Err ( Error :: Unsupported (
1370
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: JcsBgRgb ) ,
1371
+ ) ) ,
1372
+ ColorTransform :: Unknown => Err ( Error :: Format ( "Unknown colour transform" . to_string ( ) ) ) ,
1373
+ ColorTransform :: Grayscale => Err ( Error :: Unsupported (
1374
+ UnsupportedFeature :: ColorTransform ( ColorTransform :: Grayscale ) ,
1375
+ ) ) ,
1376
+ } ,
1325
1377
_ => panic ! ( ) ,
1326
1378
}
1327
1379
}
0 commit comments