diff --git a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs index 8369e9236..f5d3e7c18 100644 --- a/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/GolangPort/OrigJpegDecoderCore.cs @@ -57,25 +57,20 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort /// private bool adobeTransformValid; - /// - /// The horizontal resolution. Calculated if the image has a JFIF header. - /// - private short horizontalResolution; - /// /// Whether the image has a JFIF header /// private bool isJfif; /// - /// Whether the image has a EXIF header + /// Contains information about the JFIF marker /// - private bool isExif; + private JFifMarker jFif; /// - /// The vertical resolution. Calculated if the image has a JFIF header. + /// Whether the image has a EXIF header /// - private short verticalResolution; + private bool isExif; /// /// Initializes a new instance of the class. @@ -361,7 +356,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort break; case OrigJpegConstants.Markers.APP0: - this.ProcessApplicationHeader(remaining); + this.ProcessApplicationHeaderMarker(remaining); break; case OrigJpegConstants.Markers.APP1: this.ProcessApp1Marker(remaining); @@ -392,7 +387,76 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } } - this.InitDerivedMetaDataProperties(); + this.AssignResolution(); + } + + /// + /// Processes the application header containing the JFIF identifier plus extra data. + /// + /// The remaining bytes in the segment block. + private void ProcessApplicationHeaderMarker(int remaining) + { + if (remaining < 5) + { + // Skip the application header length + this.InputProcessor.Skip(remaining); + return; + } + + this.InputProcessor.ReadFull(this.Temp, 0, 13); + remaining -= 13; + + this.isJfif = this.Temp[0] == OrigJpegConstants.JFif.J && + this.Temp[1] == OrigJpegConstants.JFif.F && + this.Temp[2] == OrigJpegConstants.JFif.I && + this.Temp[3] == OrigJpegConstants.JFif.F && + this.Temp[4] == OrigJpegConstants.JFif.Null; + + if (this.isJfif) + { + this.jFif = new JFifMarker + { + MajorVersion = this.Temp[5], + MinorVersion = this.Temp[6], + DensityUnits = this.Temp[7], + XDensity = (short)((this.Temp[8] << 8) | this.Temp[9]), + YDensity = (short)((this.Temp[10] << 8) | this.Temp[11]) + }; + } + + // TODO: thumbnail + if (remaining > 0) + { + this.InputStream.Skip(remaining); + } + } + + /// + /// Processes the App1 marker retrieving any stored metadata + /// + /// The remaining bytes in the segment block. + private void ProcessApp1Marker(int remaining) + { + if (remaining < 6 || this.IgnoreMetadata) + { + // Skip the application header length + this.InputProcessor.Skip(remaining); + return; + } + + byte[] profile = new byte[remaining]; + this.InputProcessor.ReadFull(profile, 0, remaining); + + if (profile[0] == OrigJpegConstants.Exif.E && + profile[1] == OrigJpegConstants.Exif.X && + profile[2] == OrigJpegConstants.Exif.I && + profile[3] == OrigJpegConstants.Exif.F && + profile[4] == OrigJpegConstants.Exif.Null && + profile[5] == OrigJpegConstants.Exif.Null) + { + this.isExif = true; + this.MetaData.ExifProfile = new ExifProfile(profile); + } } /// @@ -412,16 +476,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } /// - /// Assigns derived metadata properties to , eg. horizontal and vertical resolution if it has a JFIF header. + /// Assigns the horizontal and vertical resolution to the image if it has a JFIF header or EXIF metadata. /// - private void InitDerivedMetaDataProperties() + private void AssignResolution() { - if (this.isJfif && this.horizontalResolution > 0 && this.verticalResolution > 0) - { - this.MetaData.HorizontalResolution = this.horizontalResolution; - this.MetaData.VerticalResolution = this.verticalResolution; - } - else if (this.isExif) + if (this.isExif) { ExifValue horizontal = this.MetaData.ExifProfile.GetValue(ExifTag.XResolution); ExifValue vertical = this.MetaData.ExifProfile.GetValue(ExifTag.YResolution); @@ -434,6 +493,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort this.MetaData.VerticalResolution = verticalValue; } } + else if (this.jFif.XDensity > 0 && this.jFif.YDensity > 0) + { + this.MetaData.HorizontalResolution = this.jFif.XDensity; + this.MetaData.VerticalResolution = this.jFif.YDensity; + } } /// @@ -490,29 +554,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } } - /// - /// Processes the App1 marker retrieving any stored metadata - /// - /// The remaining bytes in the segment block. - private void ProcessApp1Marker(int remaining) - { - if (remaining < 6 || this.IgnoreMetadata) - { - this.InputProcessor.Skip(remaining); - return; - } - - byte[] profile = new byte[remaining]; - this.InputProcessor.ReadFull(profile, 0, remaining); - - if (profile[0] == 'E' && profile[1] == 'x' && profile[2] == 'i' && profile[3] == 'f' && profile[4] == '\0' - && profile[5] == '\0') - { - this.isExif = true; - this.MetaData.ExifProfile = new ExifProfile(profile); - } - } - /// /// Processes the App2 marker retrieving any stored ICC profile information /// @@ -554,37 +595,6 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort } } - /// - /// Processes the application header containing the JFIF identifier plus extra data. - /// - /// The remaining bytes in the segment block. - private void ProcessApplicationHeader(int remaining) - { - if (remaining < 5) - { - this.InputProcessor.Skip(remaining); - return; - } - - this.InputProcessor.ReadFull(this.Temp, 0, 13); - remaining -= 13; - - // TODO: We should be using constants for this. - this.isJfif = this.Temp[0] == 'J' && this.Temp[1] == 'F' && this.Temp[2] == 'I' && this.Temp[3] == 'F' - && this.Temp[4] == '\x00'; - - if (this.isJfif) - { - this.horizontalResolution = (short)(this.Temp[9] + (this.Temp[8] << 8)); - this.verticalResolution = (short)(this.Temp[11] + (this.Temp[10] << 8)); - } - - if (remaining > 0) - { - this.InputProcessor.Skip(remaining); - } - } - /// /// Processes a Define Huffman Table marker, and initializes a huffman /// struct from its contents. Specified in section B.2.4.2.