Skip to content

Commit 5834e4f

Browse files
committed
Write APP14 marker if RGB color space
1 parent 83d0788 commit 5834e4f

File tree

1 file changed

+60
-3
lines changed

1 file changed

+60
-3
lines changed

src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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

Comments
 (0)