Browse Source

Merge branch 'master' into wip-323

pull/367/head
George Collins 8 years ago
committed by GitHub
parent
commit
b2dea16ab5
  1. 49
      src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs
  2. 4
      src/ImageSharp/Formats/Jpeg/JpegEncoder.cs
  3. 13
      src/ImageSharp/Formats/Png/PngDecoderCore.cs
  4. 25
      src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs
  5. 1
      src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs
  6. 1
      src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs
  7. 2
      src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs
  8. 1
      src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs
  9. 54
      tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs
  10. 1
      tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs
  11. 7
      tests/ImageSharp.Tests/ImageSharp.Tests.csproj
  12. 1
      tests/ImageSharp.Tests/TestImages.cs
  13. BIN
      tests/Images/Input/Png/big-corrupted-chunk.png

49
src/ImageSharp/Formats/Jpeg/GolangPort/JpegEncoderCore.cs

@ -125,6 +125,21 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary>
private readonly byte[] huffmanBuffer = new byte[179];
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
private readonly bool ignoreMetadata;
/// <summary>
/// The quality, that will be used to encode the image.
/// </summary>
private readonly int quality;
/// <summary>
/// Gets or sets the subsampling method to use.
/// </summary>
private readonly JpegSubsample? subsample;
/// <summary>
/// The accumulated bits to write to the stream.
/// </summary>
@ -150,37 +165,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
/// </summary>
private Stream outputStream;
/// <summary>
/// Gets or sets a value indicating whether the metadata should be ignored when the image is being decoded.
/// </summary>
private bool ignoreMetadata = false;
/// <summary>
/// Gets or sets the quality, that will be used to encode the image. Quality
/// index must be between 0 and 100 (compression from max to min).
/// </summary>
/// <value>The quality of the jpg image from 0 to 100.</value>
private int quality = 0;
/// <summary>
/// Gets or sets the subsampling method to use.
/// </summary>
private JpegSubsample? subsample;
/// <summary>
/// Initializes a new instance of the <see cref="JpegEncoderCore"/> class.
/// </summary>
/// <param name="options">The options</param>
public JpegEncoderCore(IJpegEncoderOptions options)
{
int quality = options.Quality;
if (quality == 0)
{
quality = 75;
}
this.quality = quality;
this.subsample = options.Subsample ?? (quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
// System.Drawing produces identical output for jpegs with a quality parameter of 0 and 1.
this.quality = options.Quality.Clamp(1, 100);
this.subsample = options.Subsample ?? (this.quality >= 91 ? JpegSubsample.Ratio444 : JpegSubsample.Ratio420);
this.ignoreMetadata = options.IgnoreMetadata;
}
@ -205,17 +198,15 @@ namespace SixLabors.ImageSharp.Formats.Jpeg.GolangPort
this.outputStream = stream;
int quality = this.quality.Clamp(1, 100);
// Convert from a quality rating to a scaling factor.
int scale;
if (this.quality < 50)
{
scale = 5000 / quality;
scale = 5000 / this.quality;
}
else
{
scale = 200 - (quality * 2);
scale = 200 - (this.quality * 2);
}
// Initialize the quantization tables.

4
src/ImageSharp/Formats/Jpeg/JpegEncoder.cs

@ -21,13 +21,11 @@ namespace SixLabors.ImageSharp.Formats.Jpeg
/// Gets or sets the quality, that will be used to encode the image. Quality
/// index must be between 0 and 100 (compression from max to min).
/// </summary>
/// <value>The quality of the jpg image from 0 to 100.</value>
public int Quality { get; set; }
public int Quality { get; set; } = 75;
/// <summary>
/// Gets or sets the subsample ration, that will be used to encode the image.
/// </summary>
/// <value>The subsample ratio of the jpg image.</value>
public JpegSubsample? Subsample { get; set; }
/// <summary>

13
src/ImageSharp/Formats/Png/PngDecoderCore.cs

@ -1124,12 +1124,23 @@ namespace SixLabors.ImageSharp.Formats.Png
{
var chunk = new PngChunk();
this.ReadChunkLength(chunk);
if (chunk.Length < 0)
if (chunk.Length == -1)
{
// IEND
return null;
}
if (chunk.Length < 0 || chunk.Length > this.currentStream.Length - this.currentStream.Position)
{
// Not a valid chunk so we skip back all but one of the four bytes we have just read.
// That lets us read one byte at a time until we reach a known chunk.
this.currentStream.Position -= 3;
return chunk;
}
this.ReadChunkType(chunk);
if (chunk.Type == PngChunkTypes.Data)
{
return chunk;

25
src/ImageSharp/Processing/Processors/Transforms/RotateProcessor.cs

@ -7,6 +7,7 @@ using System.Threading.Tasks;
using SixLabors.ImageSharp.Advanced;
using SixLabors.ImageSharp.Helpers;
using SixLabors.ImageSharp.Memory;
using SixLabors.ImageSharp.MetaData.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.Primitives;
@ -87,6 +88,30 @@ namespace SixLabors.ImageSharp.Processing.Processors
}
}
/// <inheritdoc/>
protected override void AfterImageApply(Image<TPixel> source, Rectangle sourceRectangle)
{
ExifProfile profile = source.MetaData.ExifProfile;
if (profile == null)
{
return;
}
if (MathF.Abs(this.Angle) < Constants.Epsilon)
{
// No need to do anything so return.
return;
}
profile.RemoveValue(ExifTag.Orientation);
if (this.Expand && profile.GetValue(ExifTag.PixelXDimension) != null)
{
profile.SetValue(ExifTag.PixelXDimension, source.Width);
profile.SetValue(ExifTag.PixelYDimension, source.Height);
}
}
/// <summary>
/// Rotates the images with an optimized method when the angle is 90, 180 or 270 degrees.
/// </summary>

1
src/ImageSharp/Quantizers/OctreeQuantizer{TPixel}.cs

@ -61,6 +61,7 @@ namespace SixLabors.ImageSharp.Quantizers
this.colors = (byte)maxColors.Clamp(1, 255);
this.octree = new Octree(this.GetBitsNeededForColorDepth(this.colors));
this.palette = null;
this.colorMap.Clear();
return base.Quantize(image, this.colors);
}

1
src/ImageSharp/Quantizers/PaletteQuantizer{TPixel}.cs

@ -58,6 +58,7 @@ namespace SixLabors.ImageSharp.Quantizers
public override QuantizedImage<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors)
{
Array.Resize(ref this.colors, maxColors.Clamp(1, 255));
this.colorMap.Clear();
return base.Quantize(image, maxColors);
}

2
src/ImageSharp/Quantizers/QuantizerBase{TPixel}.cs

@ -43,7 +43,7 @@ namespace SixLabors.ImageSharp.Quantizers.Base
public bool Dither { get; set; } = true;
/// <inheritdoc />
public IErrorDiffuser DitherType { get; set; } = new SierraLiteDiffuser();
public IErrorDiffuser DitherType { get; set; } = new FloydSteinbergDiffuser();
/// <inheritdoc/>
public virtual QuantizedImage<TPixel> Quantize(ImageFrame<TPixel> image, int maxColors)

1
src/ImageSharp/Quantizers/WuQuantizer{TPixel}.cs

@ -139,6 +139,7 @@ namespace SixLabors.ImageSharp.Quantizers
this.colors = maxColors.Clamp(1, 255);
this.palette = null;
this.colorMap.Clear();
try
{

54
tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs

@ -35,7 +35,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
public void LoadResizeSave<TPixel>(TestImageProvider<TPixel> provider, int quality, JpegSubsample subsample)
where TPixel : struct, IPixel<TPixel>
{
using (Image<TPixel> image = provider.GetImage(x=>x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })))
using (Image<TPixel> image = provider.GetImage(x => x.Resize(new ResizeOptions { Size = new Size(150, 100), Mode = ResizeMode.Max })))
{
image.MetaData.ExifProfile = null; // Reduce the size of the file
@ -62,8 +62,8 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
image.Save(outputStream, new JpegEncoder()
{
Subsample = subSample,
Quality = quality
Subsample = subSample,
Quality = quality
});
}
}
@ -83,7 +83,7 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
{
using (MemoryStream memStream = new MemoryStream())
{
input.Save(memStream, options);
input.Save(memStream, options);
memStream.Position = 0;
using (Image<Rgba32> output = Image.Load<Rgba32>(memStream))
@ -118,5 +118,51 @@ namespace SixLabors.ImageSharp.Tests.Formats.Jpg
}
}
}
[Fact]
public void Encode_Quality_0_And_1_Are_Identical()
{
var options = new JpegEncoder
{
Quality = 0
};
var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora);
using (Image<Rgba32> input = testFile.CreateImage())
using (var memStream0 = new MemoryStream())
using (var memStream1 = new MemoryStream())
{
input.SaveAsJpeg(memStream0, options);
options.Quality = 1;
input.SaveAsJpeg(memStream1, options);
Assert.Equal(memStream0.ToArray(), memStream1.ToArray());
}
}
[Fact]
public void Encode_Quality_0_And_100_Are_Not_Identical()
{
var options = new JpegEncoder
{
Quality = 0
};
var testFile = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora);
using (Image<Rgba32> input = testFile.CreateImage())
using (var memStream0 = new MemoryStream())
using (var memStream1 = new MemoryStream())
{
input.SaveAsJpeg(memStream0, options);
options.Quality = 100;
input.SaveAsJpeg(memStream1, options);
Assert.NotEqual(memStream0.ToArray(), memStream1.ToArray());
}
}
}
}

1
tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs

@ -24,6 +24,7 @@ namespace SixLabors.ImageSharp.Tests
TestImages.Png.Splash, TestImages.Png.Indexed,
TestImages.Png.FilterVar,
TestImages.Png.Bad.ChunkLength1,
TestImages.Png.Bad.CorruptedChunk,
TestImages.Png.VimImage1,
TestImages.Png.VersioningImage1,

7
tests/ImageSharp.Tests/ImageSharp.Tests.csproj

@ -17,10 +17,9 @@
</ItemGroup>
<ItemGroup>
<PackageReference Include="CoreCompat.System.Drawing" Version="1.0.0-beta006" />
<PackageReference Include="xunit" Version="2.3.0-beta4-build3742" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0-beta4-build3742" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="15.3.0" />
<PackageReference Include="Moq" Version="4.7.99" />
<PackageReference Include="xunit" Version="2.3.0" />
<PackageReference Include="xunit.runner.visualstudio" Version="2.3.0" />
<PackageReference Include="Moq" Version="4.7.137" />
<!--<PackageReference Include="StyleCop.Analyzers" Version="1.1.0-beta001">
<PrivateAssets>All</PrivateAssets>
</PackageReference>-->

1
tests/ImageSharp.Tests/TestImages.cs

@ -56,6 +56,7 @@ namespace SixLabors.ImageSharp.Tests
// Odd chunk lengths
public const string ChunkLength1 = "Png/chunklength1.png";
public const string ChunkLength2 = "Png/chunklength2.png";
public const string CorruptedChunk = "Png/big-corrupted-chunk.png";
}
public static readonly string[] All =

BIN
tests/Images/Input/Png/big-corrupted-chunk.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.0 KiB

Loading…
Cancel
Save