@@ -90,6 +90,11 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals
9090 /// </summary>
9191 private JFifMarker jFif ;
9292
93+ /// <summary>
94+ /// Whether the image has a JFIF marker. This is needed to determine, if the colorspace is YCbCr.
95+ /// </summary>
96+ private bool hasJFif ;
97+
9398 /// <summary>
9499 /// Contains information about the Adobe marker.
95100 /// </summary>
@@ -514,27 +519,75 @@ private JpegColorSpace DeduceJpegColorSpace(byte componentCount)
514519
515520 if ( componentCount == 3 )
516521 {
517- if ( ! this . adobe . Equals ( default ) && this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformUnknown )
522+ // We prioritize adobe marker over jfif marker, if somebody really encoded this image with redundant adobe marker,
523+ // then it's most likely an adobe jfif image.
524+ if ( ! this . adobe . Equals ( default ) )
518525 {
519- return JpegColorSpace . RGB ;
526+ if ( this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformYCbCr )
527+ {
528+ return JpegColorSpace . YCbCr ;
529+ }
530+
531+ if ( this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformUnknown )
532+ {
533+ return JpegColorSpace . RGB ;
534+ }
535+
536+ // Fallback to the id color deduction: If these values are 1-3 for a 3-channel image, then the image is assumed to be YCbCr.
537+ if ( this . Components [ 2 ] . Id == 3 && this . Components [ 1 ] . Id == 2 && this . Components [ 0 ] . Id == 1 )
538+ {
539+ return JpegColorSpace . YCbCr ;
540+ }
541+
542+ JpegThrowHelper . ThrowNotSupportedColorSpace ( ) ;
543+ }
544+
545+ if ( this . hasJFif )
546+ {
547+ // JFIF implies YCbCr.
548+ return JpegColorSpace . YCbCr ;
520549 }
521550
551+ // Fallback to the id color deduction.
522552 // If the component Id's are R, G, B in ASCII the colorspace is RGB and not YCbCr.
553+ // See: https://docs.oracle.com/javase/7/docs/api/javax/imageio/metadata/doc-files/jpeg_metadata.html#color
523554 if ( this . Components [ 2 ] . Id == 66 && this . Components [ 1 ] . Id == 71 && this . Components [ 0 ] . Id == 82 )
524555 {
525556 return JpegColorSpace . RGB ;
526557 }
527558
559+ // 3-channel non-subsampled images are assumed to be RGB.
560+ if ( this . Components [ 2 ] . VerticalSamplingFactor == 1 && this . Components [ 1 ] . VerticalSamplingFactor == 1 && this . Components [ 0 ] . VerticalSamplingFactor == 1 &&
561+ this . Components [ 2 ] . HorizontalSamplingFactor == 1 && this . Components [ 1 ] . HorizontalSamplingFactor == 1 && this . Components [ 0 ] . HorizontalSamplingFactor == 1 )
562+ {
563+ return JpegColorSpace . RGB ;
564+ }
565+
528566 // Some images are poorly encoded and contain incorrect colorspace transform metadata.
529567 // We ignore that and always fall back to the default colorspace.
530568 return JpegColorSpace . YCbCr ;
531569 }
532570
533571 if ( componentCount == 4 )
534572 {
535- return this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformYcck
536- ? JpegColorSpace . Ycck
537- : JpegColorSpace . Cmyk ;
573+ // jfif images doesn't not support 4 component images, so we only check adobe.
574+ if ( ! this . adobe . Equals ( default ) )
575+ {
576+ if ( this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformYcck )
577+ {
578+ return JpegColorSpace . Ycck ;
579+ }
580+
581+ if ( this . adobe . ColorTransform == JpegConstants . Adobe . ColorTransformUnknown )
582+ {
583+ return JpegColorSpace . Cmyk ;
584+ }
585+
586+ JpegThrowHelper . ThrowNotSupportedColorSpace ( ) ;
587+ }
588+
589+ // Fallback to cmyk as neither of cmyk nor ycck have 'special' component ids.
590+ return JpegColorSpace . Cmyk ;
538591 }
539592
540593 JpegThrowHelper . ThrowNotSupportedComponentCount ( componentCount ) ;
@@ -701,6 +754,8 @@ private void ExtendProfile(ref byte[] profile, byte[] extension)
701754 /// <param name="remaining">The remaining bytes in the segment block.</param>
702755 private void ProcessApplicationHeaderMarker ( BufferedReadStream stream , int remaining )
703756 {
757+ this . hasJFif = true ;
758+
704759 // We can only decode JFif identifiers.
705760 // Some images contain multiple JFIF markers (Issue 1932) so we check to see
706761 // if it's already been read.
0 commit comments