@@ -65,7 +65,11 @@ internal sealed unsafe class JpegEncoderCore : IImageEncoderInternals
6565 public JpegEncoderCore ( IJpegEncoderOptions options )
6666 {
6767 this . quality = options . Quality ;
68- this . colorType = options . ColorType ;
68+
69+ if ( IsSupportedColorType ( options . ColorType ) )
70+ {
71+ this . colorType = options . ColorType ;
72+ }
6973 }
7074
7175 /// <summary>
@@ -92,8 +96,11 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
9296 ImageMetadata metadata = image . Metadata ;
9397 JpegMetadata jpegMetadata = metadata . GetJpegMetadata ( ) ;
9498
95- // If the color type was not specified by the user, preserve the color type of the input image.
96- this . colorType ??= jpegMetadata . ColorType ;
99+ // If the color type was not specified by the user, preserve the color type of the input image, if it's a supported color type.
100+ if ( ! this . colorType . HasValue && IsSupportedColorType ( jpegMetadata . ColorType ) )
101+ {
102+ this . colorType = jpegMetadata . ColorType ;
103+ }
97104
98105 // Compute number of components based on color type in options.
99106 int componentCount = ( this . colorType == JpegColorType . Luminance ) ? 1 : 3 ;
@@ -109,6 +116,12 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
109116 // Write Exif, ICC and IPTC profiles
110117 this . WriteProfiles ( metadata ) ;
111118
119+ if ( this . colorType == JpegColorType . Rgb )
120+ {
121+ // Write App14 marker to indicate RGB color space.
122+ this . WriteApp14Marker ( ) ;
123+ }
124+
112125 // Write the quantization tables.
113126 this . WriteDefineQuantizationTables ( ref luminanceQuantTable , ref chrominanceQuantTable ) ;
114127
@@ -152,6 +165,21 @@ public void Encode<TPixel>(Image<TPixel> image, Stream stream, CancellationToken
152165 stream . Flush ( ) ;
153166 }
154167
168+ /// <summary>
169+ /// Returns true, if the color type is supported by the encoder.
170+ /// </summary>
171+ /// <param name="colorType">The color type.</param>
172+ /// <returns>true, if color type is supported.</returns>
173+ private static bool IsSupportedColorType ( JpegColorType ? colorType )
174+ {
175+ if ( colorType == JpegColorType . YCbCrRatio444 || colorType == JpegColorType . YCbCrRatio420 || colorType == JpegColorType . Luminance || colorType == JpegColorType . Rgb )
176+ {
177+ return true ;
178+ }
179+
180+ return false ;
181+ }
182+
155183 /// <summary>
156184 /// Gets the component ids.
157185 /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3.
@@ -292,6 +320,35 @@ private void WriteDefineQuantizationTables(ref Block8x8F luminanceQuantTable, re
292320 this . outputStream . Write ( dqt , 0 , dqtCount ) ;
293321 }
294322
323+ /// <summary>
324+ /// Writes the APP14 marker to indicate the image is in RGB color space.
325+ /// </summary>
326+ private void WriteApp14Marker ( )
327+ {
328+ this . WriteMarkerHeader ( JpegConstants . Markers . APP14 , 2 + AdobeMarker . Length ) ;
329+
330+ // Identifier: ASCII "Adobe".
331+ this . buffer [ 0 ] = 0x41 ;
332+ this . buffer [ 1 ] = 0x64 ;
333+ this . buffer [ 2 ] = 0x6F ;
334+ this . buffer [ 3 ] = 0x62 ;
335+ this . buffer [ 4 ] = 0x65 ;
336+
337+ // Version, currently 100.
338+ BinaryPrimitives . WriteInt16BigEndian ( this . buffer . AsSpan ( 5 , 2 ) , 100 ) ;
339+
340+ // Flags0
341+ BinaryPrimitives . WriteInt16BigEndian ( this . buffer . AsSpan ( 7 , 2 ) , 0 ) ;
342+
343+ // Flags1
344+ BinaryPrimitives . WriteInt16BigEndian ( this . buffer . AsSpan ( 9 , 2 ) , 0 ) ;
345+
346+ // Transform byte, 0 in combination with three components means the image is in RGB colorspace.
347+ this . buffer [ 11 ] = 0 ;
348+
349+ this . outputStream . Write ( this . buffer . AsSpan ( 0 , 12 ) ) ;
350+ }
351+
295352 /// <summary>
296353 /// Writes the EXIF profile.
297354 /// </summary>
0 commit comments