Browse Source

Can now preserve correct resolution for jpeg and gif.

pull/649/head
James Jackson-South 8 years ago
parent
commit
9210d4cc35
  1. 36
      src/ImageSharp/Formats/Gif/GifDecoderCore.cs
  2. 32
      src/ImageSharp/Formats/Gif/GifEncoderCore.cs
  3. 5
      src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs
  4. 10
      src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs
  5. 6
      src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs
  6. 6
      src/ImageSharp/MetaData/ImageMetaData.cs
  7. 4
      src/ImageSharp/MetaData/ResolutionUnits.cs
  8. 4
      tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs

36
src/ImageSharp/Formats/Gif/GifDecoderCore.cs

@ -450,8 +450,8 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
int index = Unsafe.Add(ref indicesRef, i);
if (this.graphicsControlExtension.TransparencyFlag == false ||
this.graphicsControlExtension.TransparencyIndex != index)
if (!this.graphicsControlExtension.TransparencyFlag
|| this.graphicsControlExtension.TransparencyIndex != index)
{
ref TPixel pixel = ref Unsafe.Add(ref rowRef, x);
rgba.Rgb = colorTable[index];
@ -516,14 +516,42 @@ namespace SixLabors.ImageSharp.Formats.Gif
/// <param name="stream">The stream containing image data. </param>
private void ReadLogicalScreenDescriptorAndGlobalColorTable(Stream stream)
{
this.metaData = new ImageMetaData();
this.stream = stream;
// Skip the identifier
this.stream.Skip(6);
this.ReadLogicalScreenDescriptor();
var meta = new ImageMetaData();
// The Pixel Aspect Ratio is defined to be the quotient of the pixel's
// width over its height. The value range in this field allows
// specification of the widest pixel of 4:1 to the tallest pixel of
// 1:4 in increments of 1/64th.
//
// Values : 0 - No aspect ratio information is given.
// 1..255 - Value used in the computation.
//
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
if (this.logicalScreenDescriptor.PixelAspectRatio > 0)
{
meta.ResolutionUnits = ResolutionUnits.AspectRatio;
float ratio = (this.logicalScreenDescriptor.PixelAspectRatio + 15) / 64F;
if (ratio > 1)
{
meta.HorizontalResolution = ratio;
meta.VerticalResolution = 1;
}
else
{
meta.VerticalResolution = 1 / ratio;
meta.HorizontalResolution = 1;
}
}
this.metaData = meta;
if (this.logicalScreenDescriptor.GlobalColorTableFlag)
{
int globalColorTableLength = this.logicalScreenDescriptor.GlobalColorTableSize * 3;

32
src/ImageSharp/Formats/Gif/GifEncoderCore.cs

@ -226,11 +226,41 @@ namespace SixLabors.ImageSharp.Formats.Gif
{
byte packedValue = GifLogicalScreenDescriptor.GetPackedValue(useGlobalTable, this.bitDepth - 1, false, this.bitDepth - 1);
// The Pixel Aspect Ratio is defined to be the quotient of the pixel's
// width over its height. The value range in this field allows
// specification of the widest pixel of 4:1 to the tallest pixel of
// 1:4 in increments of 1/64th.
//
// Values : 0 - No aspect ratio information is given.
// 1..255 - Value used in the computation.
//
// Aspect Ratio = (Pixel Aspect Ratio + 15) / 64
ImageMetaData meta = image.MetaData;
byte ratio = 0;
if (meta.ResolutionUnits == ResolutionUnits.AspectRatio)
{
double hr = meta.HorizontalResolution;
double vr = meta.VerticalResolution;
if (hr != vr)
{
if (hr > vr)
{
ratio = (byte)((hr * 64) - 15);
}
else
{
ratio = (byte)(((1 / vr) * 64) - 15);
}
}
}
var descriptor = new GifLogicalScreenDescriptor(
width: (ushort)image.Width,
height: (ushort)image.Height,
packed: packedValue,
backgroundColorIndex: unchecked((byte)transparencyIndex));
backgroundColorIndex: unchecked((byte)transparencyIndex),
ratio);
descriptor.WriteTo(this.buffer);

5
src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs

@ -2,6 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using System;
using SixLabors.ImageSharp.MetaData;
namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
{
@ -31,7 +32,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
this.MajorVersion = majorVersion;
this.MinorVersion = minorVersion;
this.DensityUnits = densityUnits;
this.DensityUnits = (ResolutionUnits)densityUnits;
this.XDensity = xDensity;
this.YDensity = yDensity;
}
@ -52,7 +53,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder
/// 01 : Pixels per inch (2.54 cm)
/// 02 : Pixels per centimeter
/// </summary>
public byte DensityUnits { get; }
public ResolutionUnits DensityUnits { get; }
/// <summary>
/// Gets the horizontal pixel density. Must not be zero.

10
src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs

@ -210,7 +210,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
int componentCount = 3;
// Write the Start Of Image marker.
this.WriteApplicationHeader((short)image.MetaData.HorizontalResolution, (short)image.MetaData.VerticalResolution);
this.WriteApplicationHeader(
(byte)image.MetaData.ResolutionUnits,
(short)image.MetaData.HorizontalResolution,
(short)image.MetaData.VerticalResolution);
this.WriteProfiles(image);
@ -425,9 +428,10 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// <summary>
/// Writes the application header containing the JFIF identifier plus extra data.
/// </summary>
/// <param name="resolutionUnits">The resolution unit of measurement.</param>
/// <param name="horizontalResolution">The resolution of the image in the x- direction.</param>
/// <param name="verticalResolution">The resolution of the image in the y- direction.</param>
private void WriteApplicationHeader(short horizontalResolution, short verticalResolution)
private void WriteApplicationHeader(byte resolutionUnits, short horizontalResolution, short verticalResolution)
{
// Write the start of image marker. Markers are always prefixed with with 0xff.
this.buffer[0] = JpegConstants.Markers.XFF;
@ -445,7 +449,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
this.buffer[10] = 0x00; // = "JFIF",'\0'
this.buffer[11] = 0x01; // versionhi
this.buffer[12] = 0x01; // versionlo
this.buffer[13] = 0x01; // xyunits as dpi
this.buffer[13] = resolutionUnits; // xyunits
// Resolution. Big Endian
this.buffer[14] = (byte)(horizontalResolution >> 8);

6
src/ImageSharp/Formats/Jpeg/PdfJsPort/PdfJsJpegDecoderCore.cs

@ -412,6 +412,7 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
{
this.MetaData.HorizontalResolution = this.jFif.XDensity;
this.MetaData.VerticalResolution = this.jFif.YDensity;
this.MetaData.ResolutionUnits = this.jFif.DensityUnits;
}
else if (this.isExif)
{
@ -423,10 +424,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.PdfJsPort
? ((Rational)verticalTag.Value).ToDouble()
: 0;
byte units = this.MetaData.ExifProfile.TryGetValue(ExifTag.ResolutionUnit, out ExifValue resolutionTag)
? (byte)(((ushort)resolutionTag.Value) - 1) // EXIF is 1,2,3
: byte.MinValue;
if (horizontalValue > 0 && verticalValue > 0)
{
this.MetaData.HorizontalResolution = horizontalValue;
this.MetaData.VerticalResolution = verticalValue;
this.MetaData.ResolutionUnits = (ResolutionUnits)units;
}
}

6
src/ImageSharp/MetaData/ImageMetaData.cs

@ -47,6 +47,7 @@ namespace SixLabors.ImageSharp.MetaData
{
this.HorizontalResolution = other.HorizontalResolution;
this.VerticalResolution = other.VerticalResolution;
this.ResolutionUnits = other.ResolutionUnits;
this.RepeatCount = other.RepeatCount;
foreach (ImageProperty property in other.Properties)
@ -99,6 +100,11 @@ namespace SixLabors.ImageSharp.MetaData
}
}
/// <summary>
/// Gets or sets unit of measure used when reporting resolution.
/// </summary>
public ResolutionUnits ResolutionUnits { get; set; } = ResolutionUnits.PixelsPerInch;
/// <summary>
/// Gets or sets the Exif profile.
/// </summary>

4
src/ImageSharp/Formats/DensityUnits.cs → src/ImageSharp/MetaData/ResolutionUnits.cs

@ -1,12 +1,12 @@
// Copyright (c) Six Labors and contributors.
// Licensed under the Apache License, Version 2.0.
namespace SixLabors.ImageSharp.Formats
namespace SixLabors.ImageSharp.MetaData
{
/// <summary>
/// Provides enumeration of available pixel density units.
/// </summary>
public enum DensityUnits : byte
public enum ResolutionUnits : byte
{
/// <summary>
/// No units; width:height pixel aspect ratio = Ydensity:Xdensity

4
tests/ImageSharp.Tests/Formats/Jpg/JFifMarkerTests.cs

@ -2,7 +2,7 @@
// Licensed under the Apache License, Version 2.0.
using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder;
using SixLabors.ImageSharp.MetaData;
using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.Jpg
@ -32,7 +32,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
Assert.True(isJFif);
Assert.Equal(1, marker.MajorVersion);
Assert.Equal(1, marker.MinorVersion);
Assert.Equal(1, marker.DensityUnits);
Assert.Equal(ResolutionUnits.PixelsPerInch, marker.DensityUnits);
Assert.Equal(96, marker.XDensity);
Assert.Equal(96, marker.YDensity);
}

Loading…
Cancel
Save