diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 7174b6d50d..546de74dac 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -65,7 +65,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg public JpegEncoderCore(IJpegEncoderOptions options) { this.quality = options.Quality; - this.colorType = options.ColorType; + + if (IsSupportedColorType(options.ColorType)) + { + this.colorType = options.ColorType; + } } /// @@ -92,8 +96,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg ImageMetadata metadata = image.Metadata; JpegMetadata jpegMetadata = metadata.GetJpegMetadata(); - // If the color type was not specified by the user, preserve the color type of the input image. - this.colorType ??= jpegMetadata.ColorType; + // 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. + if (!this.colorType.HasValue && IsSupportedColorType(jpegMetadata.ColorType)) + { + this.colorType = jpegMetadata.ColorType; + } // Compute number of components based on color type in options. int componentCount = (this.colorType == JpegColorType.Luminance) ? 1 : 3; @@ -109,6 +116,12 @@ namespace SixLabors.ImageSharp.Formats.Jpeg // Write Exif, ICC and IPTC profiles this.WriteProfiles(metadata); + if (this.colorType == JpegColorType.Rgb) + { + // Write App14 marker to indicate RGB color space. + this.WriteApp14Marker(); + } + // Write the quantization tables. this.WriteDefineQuantizationTables(ref luminanceQuantTable, ref chrominanceQuantTable); @@ -152,6 +165,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg stream.Flush(); } + /// + /// Returns true, if the color type is supported by the encoder. + /// + /// The color type. + /// true, if color type is supported. + private static bool IsSupportedColorType(JpegColorType? colorType) + { + if (colorType == JpegColorType.YCbCrRatio444 || colorType == JpegColorType.YCbCrRatio420 || colorType == JpegColorType.Luminance || colorType == JpegColorType.Rgb) + { + return true; + } + + return false; + } + /// /// Gets the component ids. /// For color space RGB this will be RGB as ASCII, otherwise 1, 2, 3. @@ -292,6 +320,35 @@ namespace SixLabors.ImageSharp.Formats.Jpeg this.outputStream.Write(dqt, 0, dqtCount); } + /// + /// Writes the APP14 marker to indicate the image is in RGB color space. + /// + private void WriteApp14Marker() + { + this.WriteMarkerHeader(JpegConstants.Markers.APP14, 2 + AdobeMarker.Length); + + // Identifier: ASCII "Adobe". + this.buffer[0] = 0x41; + this.buffer[1] = 0x64; + this.buffer[2] = 0x6F; + this.buffer[3] = 0x62; + this.buffer[4] = 0x65; + + // Version, currently 100. + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(5, 2), 100); + + // Flags0 + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(7, 2), 0); + + // Flags1 + BinaryPrimitives.WriteInt16BigEndian(this.buffer.AsSpan(9, 2), 0); + + // Transform byte, 0 in combination with three components means the image is in RGB colorspace. + this.buffer[11] = 0; + + this.outputStream.Write(this.buffer.AsSpan(0, 12)); + } + /// /// Writes the EXIF profile. ///