@@ -38,15 +38,15 @@ public class JpegEncoderTests
3838 public static readonly TheoryData < JpegColorType , int > BitsPerPixel_Quality =
3939 new TheoryData < JpegColorType , int >
4040 {
41- { JpegColorType . Rgb , 40 } ,
42- { JpegColorType . Rgb , 60 } ,
43- { JpegColorType . Rgb , 100 } ,
4441 { JpegColorType . YCbCrRatio420 , 40 } ,
4542 { JpegColorType . YCbCrRatio420 , 60 } ,
4643 { JpegColorType . YCbCrRatio420 , 100 } ,
4744 { JpegColorType . YCbCrRatio444 , 40 } ,
4845 { JpegColorType . YCbCrRatio444 , 60 } ,
4946 { JpegColorType . YCbCrRatio444 , 100 } ,
47+ { JpegColorType . Rgb , 40 } ,
48+ { JpegColorType . Rgb , 60 } ,
49+ { JpegColorType . Rgb , 100 }
5050 } ;
5151
5252 public static readonly TheoryData < int > Grayscale_Quality =
@@ -87,6 +87,51 @@ public void Encode_PreservesColorType<TPixel>(TestImageProvider<TPixel> provider
8787 Assert . Equal ( expectedColorType , meta . ColorType ) ;
8888 }
8989
90+ [ Theory ]
91+ [ WithFile ( TestImages . Jpeg . Baseline . Cmyk , PixelTypes . Rgba32 ) ]
92+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg410 , PixelTypes . Rgba32 ) ]
93+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg411 , PixelTypes . Rgba32 ) ]
94+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg422 , PixelTypes . Rgba32 ) ]
95+ public void Encode_WithUnsupportedColorType_FromInput_DefaultsToYCbCr420 < TPixel > ( TestImageProvider < TPixel > provider )
96+ where TPixel : unmanaged, IPixel < TPixel >
97+ {
98+ // arrange
99+ using Image < TPixel > input = provider . GetImage ( JpegDecoder ) ;
100+ using var memoryStream = new MemoryStream ( ) ;
101+
102+ // act
103+ input . Save ( memoryStream , JpegEncoder ) ;
104+
105+ // assert
106+ memoryStream . Position = 0 ;
107+ using var output = Image . Load < Rgba32 > ( memoryStream ) ;
108+ JpegMetadata meta = output . Metadata . GetJpegMetadata ( ) ;
109+ Assert . Equal ( JpegColorType . YCbCrRatio420 , meta . ColorType ) ;
110+ }
111+
112+ [ Theory ]
113+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg444 , PixelTypes . Rgba32 , JpegColorType . Cmyk ) ]
114+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg444 , PixelTypes . Rgba32 , JpegColorType . YCbCrRatio410 ) ]
115+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg444 , PixelTypes . Rgba32 , JpegColorType . YCbCrRatio411 ) ]
116+ [ WithFile ( TestImages . Jpeg . Baseline . Jpeg444 , PixelTypes . Rgba32 , JpegColorType . YCbCrRatio422 ) ]
117+ public void Encode_WithUnsupportedColorType_DefaultsToYCbCr420 < TPixel > ( TestImageProvider < TPixel > provider , JpegColorType colorType )
118+ where TPixel : unmanaged, IPixel < TPixel >
119+ {
120+ // arrange
121+ var jpegEncoder = new JpegEncoder ( ) { ColorType = colorType } ;
122+ using var input = new Image < Rgb24 > ( 10 , 10 ) ;
123+ using var memoryStream = new MemoryStream ( ) ;
124+
125+ // act
126+ input . Save ( memoryStream , jpegEncoder ) ;
127+
128+ // assert
129+ memoryStream . Position = 0 ;
130+ using var output = Image . Load < Rgba32 > ( memoryStream ) ;
131+ JpegMetadata meta = output . Metadata . GetJpegMetadata ( ) ;
132+ Assert . Equal ( JpegColorType . YCbCrRatio420 , meta . ColorType ) ;
133+ }
134+
90135 [ Theory ]
91136 [ MemberData ( nameof ( QualityFiles ) ) ]
92137 public void Encode_PreservesQuality ( string imagePath , int quality )
@@ -111,16 +156,24 @@ public void Encode_PreservesQuality(string imagePath, int quality)
111156 [ Theory ]
112157 [ WithFile ( TestImages . Png . CalliphoraPartial , nameof ( BitsPerPixel_Quality ) , PixelTypes . Rgba32 ) ]
113158 [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 73 , 71 , PixelTypes . Rgba32 ) ]
114- [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 48 , 24 , PixelTypes . Rgba32 ) ]
115- [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 46 , 8 , PixelTypes . Rgba32 ) ]
116- [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 51 , 7 , PixelTypes . Rgba32 ) ]
117- [ WithSolidFilledImages ( nameof ( BitsPerPixel_Quality ) , 1 , 1 , 255 , 100 , 50 , 255 , PixelTypes . Rgba32 ) ]
118- [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 7 , 5 , PixelTypes . Rgba32 ) ]
159+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 96 , 48 , PixelTypes . Rgba32 ) ]
160+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 138 , 24 , PixelTypes . Rgba32 ) ]
161+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 153 , 21 , PixelTypes . Rgba32 ) ]
119162 [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 600 , 400 , PixelTypes . Rgba32 ) ]
120- [ WithSolidFilledImages ( nameof ( BitsPerPixel_Quality ) , 1 , 1 , 100 , 100 , 100 , 255 , PixelTypes . L8 ) ]
121163 public void EncodeBaseline_WorksWithDifferentSizes < TPixel > ( TestImageProvider < TPixel > provider , JpegColorType colorType , int quality )
122164 where TPixel : unmanaged, IPixel < TPixel > => TestJpegEncoderCore ( provider , colorType , quality ) ;
123165
166+ [ Theory ]
167+ [ WithSolidFilledImages ( nameof ( BitsPerPixel_Quality ) , 1 , 1 , 255 , 100 , 50 , 255 , PixelTypes . Rgba32 ) ]
168+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 7 , 5 , PixelTypes . Rgba32 ) ]
169+ [ WithSolidFilledImages ( nameof ( BitsPerPixel_Quality ) , 1 , 1 , 100 , 100 , 100 , 255 , PixelTypes . L8 ) ]
170+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 48 , 24 , PixelTypes . Rgba32 ) ]
171+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 46 , 8 , PixelTypes . Rgba32 ) ]
172+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 51 , 7 , PixelTypes . Rgba32 ) ]
173+
174+ public void EncodeBaseline_WithSmallImages_WorksWithDifferentSizes < TPixel > ( TestImageProvider < TPixel > provider , JpegColorType colorType , int quality )
175+ where TPixel : unmanaged, IPixel < TPixel > => TestJpegEncoderCore ( provider , colorType , quality , comparer : ImageComparer . Tolerant ( 0.12f ) ) ;
176+
124177 [ Theory ]
125178 [ WithFile ( TestImages . Png . BikeGrayscale , nameof ( Grayscale_Quality ) , PixelTypes . L8 ) ]
126179 [ WithSolidFilledImages ( 1 , 1 , 100 , 100 , 100 , 255 , PixelTypes . Rgba32 , 100 ) ]
@@ -132,10 +185,15 @@ public void EncodeBaseline_Grayscale<TPixel>(TestImageProvider<TPixel> provider,
132185 where TPixel : unmanaged, IPixel < TPixel > => TestJpegEncoderCore ( provider , JpegColorType . Luminance , quality ) ;
133186
134187 [ Theory ]
135- [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 48 , 48 , PixelTypes . Rgba32 | PixelTypes . Bgra32 ) ]
188+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 96 , 96 , PixelTypes . Rgba32 | PixelTypes . Bgra32 ) ]
136189 public void EncodeBaseline_IsNotBoundToSinglePixelType < TPixel > ( TestImageProvider < TPixel > provider , JpegColorType colorType , int quality )
137190 where TPixel : unmanaged, IPixel < TPixel > => TestJpegEncoderCore ( provider , colorType , quality ) ;
138191
192+ [ Theory ]
193+ [ WithTestPatternImages ( nameof ( BitsPerPixel_Quality ) , 48 , 48 , PixelTypes . Rgba32 | PixelTypes . Bgra32 ) ]
194+ public void EncodeBaseline_WithSmallImages_IsNotBoundToSinglePixelType < TPixel > ( TestImageProvider < TPixel > provider , JpegColorType colorType , int quality )
195+ where TPixel : unmanaged, IPixel < TPixel > => TestJpegEncoderCore ( provider , colorType , quality , comparer : ImageComparer . Tolerant ( 0.06f ) ) ;
196+
139197 [ Theory ]
140198 [ WithFile ( TestImages . Png . CalliphoraPartial , PixelTypes . Rgba32 , JpegColorType . YCbCrRatio444 ) ]
141199 [ WithTestPatternImages ( 587 , 821 , PixelTypes . Rgba32 , JpegColorType . YCbCrRatio444 ) ]
@@ -161,11 +219,11 @@ private static ImageComparer GetComparer(int quality, JpegColorType? colorType)
161219
162220 if ( quality < 50 )
163221 {
164- tolerance *= 10f ;
222+ tolerance *= 2.5f ;
165223 }
166224 else if ( quality < 75 || colorType == JpegColorType . YCbCrRatio420 )
167225 {
168- tolerance *= 5f ;
226+ tolerance *= 1. 5f;
169227 if ( colorType == JpegColorType . YCbCrRatio420 )
170228 {
171229 tolerance *= 2f ;
0 commit comments