Browse Source

Add webp EXIF tests

pull/1552/head
Brian Popow 5 years ago
parent
commit
1eb7307d82
  1. 6
      src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs
  2. 4
      src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs
  3. 10
      src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs
  4. 2
      src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs
  5. 20
      src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs
  6. 2
      src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs
  7. 43
      src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs
  8. 6
      src/ImageSharp/Formats/WebP/WebpDecoderCore.cs
  9. 15
      tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs
  10. 2
      tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs
  11. 2
      tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs
  12. 2
      tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs
  13. 46
      tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

6
src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs

@ -369,7 +369,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
this.nbBits -= 8;
if ((bits & 0xff) != 0xff)
{
var pos = this.pos;
uint pos = this.pos;
this.BitWriterResize(this.run + 1);
if ((bits & 0x100) != 0)
@ -509,7 +509,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
private void WriteFilterHeader(Vp8BitWriter bitWriter)
{
Vp8FilterHeader hdr = this.enc.FilterHeader;
var useLfDelta = hdr.I4x4LfDelta != 0;
bool useLfDelta = hdr.I4x4LfDelta != 0;
bitWriter.PutBitUniform(hdr.Simple ? 1 : 0);
bitWriter.PutBits((uint)hdr.FilterLevel, 6);
bitWriter.PutBits((uint)hdr.Sharpness, 3);
@ -645,7 +645,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
uint profile = 0;
int width = this.enc.Width;
int height = this.enc.Height;
var vp8FrameHeader = new byte[WebpConstants.Vp8FrameHeaderSize];
byte[] vp8FrameHeader = new byte[WebpConstants.Vp8FrameHeaderSize];
// Paragraph 9.1.
uint bits = 0 // keyframe (1b)

4
src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs

@ -108,7 +108,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
public Vp8LBitWriter Clone()
{
var clonedBuffer = new byte[this.Buffer.Length];
byte[] clonedBuffer = new byte[this.Buffer.Length];
System.Buffer.BlockCopy(this.Buffer, 0, clonedBuffer, 0, this.cur);
return new Vp8LBitWriter(clonedBuffer, this.bits, this.used, this.cur);
}
@ -186,7 +186,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.BitWriter
// If needed, make some room by flushing some bits out.
if (this.cur + WriterBytes > this.end)
{
var extraSize = this.end - this.cur + MinExtraSize;
int extraSize = this.end - this.cur + MinExtraSize;
this.BitWriterResize(extraSize);
}

10
src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs

@ -230,7 +230,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static void BackwardReferencesTraceBackwards(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChain, Vp8LBackwardRefs refsSrc, Vp8LBackwardRefs refsDst)
{
int distArraySize = xSize * ySize;
var distArray = new ushort[distArraySize];
ushort[] distArray = new ushort[distArraySize];
BackwardReferencesHashChainDistanceOnly(xSize, ySize, bgra, cacheBits, hashChain, refsSrc, distArray);
int chosenPathSize = TraceBackwards(distArray, distArraySize);
@ -242,7 +242,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
{
int pixCount = xSize * ySize;
bool useColorCache = cacheBits > 0;
var literalArraySize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + ((cacheBits > 0) ? (1 << cacheBits) : 0);
int literalArraySize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + ((cacheBits > 0) ? (1 << cacheBits) : 0);
var costModel = new CostModel(literalArraySize);
int offsetPrev = -1;
int lenPrev = -1;
@ -511,11 +511,11 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
private static void BackwardReferencesLz77Box(int xSize, int ySize, Span<uint> bgra, int cacheBits, Vp8LHashChain hashChainBest, Vp8LHashChain hashChain, Vp8LBackwardRefs refs)
{
int pixelCount = xSize * ySize;
var windowOffsets = new int[WindowOffsetsSizeMax];
var windowOffsetsNew = new int[WindowOffsetsSizeMax];
int[] windowOffsets = new int[WindowOffsetsSizeMax];
int[] windowOffsetsNew = new int[WindowOffsetsSizeMax];
int windowOffsetsSize = 0;
int windowOffsetsNewSize = 0;
var counts = new short[xSize * ySize];
short[] counts = new short[xSize * ySize];
int bestOffsetPrev = -1;
int bestLengthPrev = -1;

2
src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs

@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
/// <summary>
/// Returns the exact index where array1 and array2 are different. For an index
/// inferior or equal to bestLenMatch, the return value just has to be strictly
/// inferior to best_lenMatch. The current behavior is to return 0 if this index
/// inferior to bestLenMatch match. The current behavior is to return 0 if this index
/// is bestLenMatch, and the index itself otherwise.
/// If no two elements are the same, it returns maxLimit.
/// </summary>

20
src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs

@ -94,8 +94,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
int maxTileSize = 1 << bits;
int tileXSize = LosslessUtils.SubSampleSize(width, bits);
int tileYSize = LosslessUtils.SubSampleSize(height, bits);
var accumulatedRedHisto = new int[256];
var accumulatedBlueHisto = new int[256];
int[] accumulatedRedHisto = new int[256];
int[] accumulatedBlueHisto = new int[256];
var prevX = default(Vp8LMultipliers);
var prevY = default(Vp8LMultipliers);
for (int tileY = 0; tileY < tileYSize; tileY++)
@ -204,9 +204,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
Span<byte> maxDiffs = MemoryMarshal.Cast<uint, byte>(currentRow.Slice(width + 1));
float bestDiff = MaxDiffCost;
int bestMode = 0;
var residuals = new uint[1 << WebpConstants.MaxTransformBits];
var histoArgb = new int[4][];
var bestHisto = new int[4][];
uint[] residuals = new uint[1 << WebpConstants.MaxTransformBits];
int[][] histoArgb = new int[4][];
int[][] bestHisto = new int[4][];
for (int i = 0; i < 4; i++)
{
histoArgb[i] = new int[256];
@ -260,7 +260,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
}
}
var curDiff = PredictionCostSpatialHistogram(accumulated, histoArgb);
float curDiff = PredictionCostSpatialHistogram(accumulated, histoArgb);
// Favor keeping the areas locally similar.
if (mode == leftMode)
@ -448,7 +448,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
return LosslessUtils.SubPixels(value, predict);
}
var quantization = maxQuantization;
int quantization = maxQuantization;
while (quantization >= maxDiff)
{
quantization >>= 1;
@ -464,7 +464,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
a = NearLosslessComponent((byte)(value >> 24), (byte)(predict >> 24), 0xff, quantization);
}
var g = NearLosslessComponent((byte)((value >> 8) & 0xff), (byte)((predict >> 8) & 0xff), 0xff, quantization);
byte g = NearLosslessComponent((byte)((value >> 8) & 0xff), (byte)((predict >> 8) & 0xff), 0xff, quantization);
if (usedSubtractGreen)
{
@ -478,8 +478,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
greenDiff = NearLosslessDiff(newGreen, (byte)((value >> 8) & 0xff));
}
var r = NearLosslessComponent(NearLosslessDiff((byte)((value >> 16) & 0xff), greenDiff), (byte)((predict >> 16) & 0xff), (byte)(0xff - newGreen), quantization);
var b = NearLosslessComponent(NearLosslessDiff((byte)(value & 0xff), greenDiff), (byte)(predict & 0xff), (byte)(0xff - newGreen), quantization);
byte r = NearLosslessComponent(NearLosslessDiff((byte)((value >> 16) & 0xff), greenDiff), (byte)((predict >> 16) & 0xff), (byte)(0xff - newGreen), quantization);
byte b = NearLosslessComponent(NearLosslessDiff((byte)(value & 0xff), greenDiff), (byte)(predict & 0xff), (byte)(0xff - newGreen), quantization);
return ((uint)a << 24) | ((uint)r << 16) | ((uint)g << 8) | b;
}

2
src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs

@ -172,6 +172,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless
public void Encode<TPixel>(Image<TPixel> image, Stream stream)
where TPixel : unmanaged, IPixel<TPixel>
{
image.Metadata.SyncProfiles();
// Write the image size.
int width = image.Width;
int height = image.Height;

43
src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs

@ -98,10 +98,10 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
: (method >= 3) ? Vp8RdLevel.RdOptBasic
: Vp8RdLevel.RdOptNone;
var pixelCount = width * height;
int pixelCount = width * height;
this.Mbw = (width + 15) >> 4;
this.Mbh = (height + 15) >> 4;
var uvSize = ((width + 1) >> 1) * ((height + 1) >> 1);
int uvSize = ((width + 1) >> 1) * ((height + 1) >> 1);
this.Y = this.memoryAllocator.Allocate<byte>(pixelCount);
this.U = this.memoryAllocator.Allocate<byte>(uvSize);
this.V = this.memoryAllocator.Allocate<byte>(uvSize);
@ -274,7 +274,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
int uvStride = (yStride + 1) >> 1;
var it = new Vp8EncIterator(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh);
var alphas = new int[WebpConstants.MaxAlpha + 1];
int[] alphas = new int[WebpConstants.MaxAlpha + 1];
this.alpha = this.MacroBlockAnalysis(width, height, it, y, u, v, yStride, uvStride, alphas, out this.uvAlpha);
int totalMb = this.Mbw * this.Mbw;
this.alpha /= totalMb;
@ -321,6 +321,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
this.AdjustFilterStrength();
// Write bytes from the bitwriter buffer to the stream.
image.Metadata.SyncProfiles();
this.bitWriter.WriteEncodedImageToStream(stream, image.Metadata.ExifProfile, (uint)width, (uint)height);
}
@ -367,7 +368,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
while (numPassLeft-- > 0)
{
bool isLastPass = (MathF.Abs(stats.Dq) <= DqLimit) || (numPassLeft == 0) || (this.maxI4HeaderBits == 0);
var sizeP0 = this.OneStatPass(width, height, yStride, uvStride, rdOpt, nbMbs, stats);
long sizeP0 = this.OneStatPass(width, height, yStride, uvStride, rdOpt, nbMbs, stats);
if (sizeP0 == 0)
{
return;
@ -517,25 +518,25 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private void AssignSegments(int[] alphas)
{
int nb = (this.SegmentHeader.NumSegments < NumMbSegments) ? this.SegmentHeader.NumSegments : NumMbSegments;
var centers = new int[NumMbSegments];
int[] centers = new int[NumMbSegments];
int weightedAverage = 0;
var map = new int[WebpConstants.MaxAlpha + 1];
int[] map = new int[WebpConstants.MaxAlpha + 1];
int n, k;
var accum = new int[NumMbSegments];
var distAccum = new int[NumMbSegments];
int[] accum = new int[NumMbSegments];
int[] distAccum = new int[NumMbSegments];
// Bracket the input.
for (n = 0; n <= WebpConstants.MaxAlpha && alphas[n] == 0; ++n)
{
}
var minA = n;
int minA = n;
for (n = WebpConstants.MaxAlpha; n > minA && alphas[n] == 0; --n)
{
}
var maxA = n;
var rangeA = maxA - minA;
int maxA = n;
int rangeA = maxA - minA;
// Spread initial centers evenly.
for (k = 0, n = 1; k < nb; ++k, n += 2)
@ -573,9 +574,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
}
// All point are classified. Move the centroids to the center of their respective cloud.
var displaced = 0;
int displaced = 0;
weightedAverage = 0;
var totalWeight = 0;
int totalWeight = 0;
for (n = 0; n < nb; ++n)
{
if (accum[n] != 0)
@ -694,7 +695,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private void SetupFilterStrength()
{
var filterSharpness = 0; // TODO: filterSharpness is hardcoded
int filterSharpness = 0; // TODO: filterSharpness is hardcoded
var filterType = 1; // TODO: filterType is hardcoded
// level0 is in [0..500]. Using '-f 50' as filter_strength is mid-filtering.
@ -720,7 +721,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private void SetSegmentProbas()
{
var p = new int[NumMbSegments];
int[] p = new int[NumMbSegments];
int n;
for (n = 0; n < this.Mbw * this.Mbh; ++n)
@ -1078,7 +1079,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
// i16x16
residual.Init(0, 1, this.Proba);
residual.SetCoeffs(rd.YDcLevels);
var res = residual.RecordCoeffs(it.TopNz[8] + it.LeftNz[8]);
int res = residual.RecordCoeffs(it.TopNz[8] + it.LeftNz[8]);
it.TopNz[8] = res;
it.LeftNz[8] = res;
residual.Init(1, 0, this.Proba);
@ -1128,8 +1129,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Span<byte> src = it.YuvIn.AsSpan(Vp8EncIterator.YOffEnc);
int nz = 0;
int n;
var dcTmp = new short[16];
var tmp = new short[16 * 16];
short[] dcTmp = new short[16];
short[] tmp = new short[16 * 16];
Span<short> tmpSpan = tmp.AsSpan();
for (n = 0; n < 16; n += 2)
@ -1161,9 +1162,9 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
private int ReconstructIntra4(Vp8EncIterator it, Vp8SegmentInfo dqm, Span<short> levels, Span<byte> src, Span<byte> yuvOut, int mode)
{
Span<byte> reference = it.YuvP.AsSpan(Vp8Encoding.Vp8I4ModeOffsets[mode]);
var tmp = new short[16];
short[] tmp = new short[16];
Vp8Encoding.FTransform(src, reference, tmp);
var nz = QuantEnc.QuantizeBlock(tmp, levels, dqm.Y1);
int nz = QuantEnc.QuantizeBlock(tmp, levels, dqm.Y1);
Vp8Encoding.ITransform(reference, tmp, yuvOut, false);
return nz;
@ -1175,7 +1176,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossy
Span<byte> src = it.YuvIn.AsSpan(Vp8EncIterator.UOffEnc);
int nz = 0;
int n;
var tmp = new short[8 * 16];
short[] tmp = new short[8 * 16];
for (n = 0; n < 8; n += 2)
{

6
src/ImageSharp/Formats/WebP/WebpDecoderCore.cs

@ -84,11 +84,11 @@ namespace SixLabors.ImageSharp.Formats.Webp
this.Metadata = new ImageMetadata();
this.currentStream = stream;
var fileSize = this.ReadImageHeader();
uint fileSize = this.ReadImageHeader();
using (this.webImageInfo = this.ReadVp8Info())
{
if (this.webImageInfo.Features != null && this.webImageInfo.Features.Animation)
if (this.webImageInfo.Features is { Animation: true })
{
WebpThrowHelper.ThrowNotSupportedException("Animations are not supported");
}
@ -384,7 +384,7 @@ namespace SixLabors.ImageSharp.Formats.Webp
// The first 28 bits of the bitstream specify the width and height of the image.
uint width = bitReader.ReadValue(WebpConstants.Vp8LImageSizeBits) + 1;
uint height = bitReader.ReadValue(WebpConstants.Vp8LImageSizeBits) + 1;
if (width == 1 || height == 1)
if (width == 0 || height == 0)
{
WebpThrowHelper.ThrowImageFormatException("invalid width or height read");
}

15
tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs

@ -8,7 +8,6 @@
using System.IO;
using BenchmarkDotNet.Attributes;
using SixLabors.ImageSharp.PixelFormats;
using SixLabors.ImageSharp.Tests;
@ -26,8 +25,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
private byte[] data;
private Configuration configuration;
#if BIG_TESTS
private static readonly int BufferSize = 1024 * 68;
@ -61,16 +58,6 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public string TestImage { get; set; }
#endif
[GlobalSetup]
public void Config()
{
if (this.configuration == null)
{
this.configuration = new Configuration();
this.configuration.StreamProcessingBufferSize = BufferSize;
}
}
[IterationSetup]
public void ReadImages()
{
@ -95,7 +82,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs
public Size TiffCore()
{
using (var ms = new MemoryStream(this.data))
using (var image = Image.Load<Rgba32>(this.configuration, ms))
using (var image = Image.Load<Rgba32>(ms))
{
return image.Size();
}

2
tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs

@ -11,6 +11,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[MarkdownExporter]
[HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))]
public class DecodeWebp
{

2
tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs

@ -10,6 +10,8 @@ using SixLabors.ImageSharp.Tests;
namespace SixLabors.ImageSharp.Benchmarks.Codecs
{
[MarkdownExporter]
[HtmlExporter]
[Config(typeof(Config.ShortMultiFramework))]
public class EncodeWebp
{

2
tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs

@ -13,7 +13,7 @@ using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP
{
[Trait("Format", "Webp")]
[Trait("Format", "WebpLossless")]
public class PredictorEncoderTests
{
[Fact]

46
tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs

@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using SixLabors.ImageSharp.Formats.Webp;
using SixLabors.ImageSharp.Metadata;
using SixLabors.ImageSharp.Metadata.Profiles.Exif;
using SixLabors.ImageSharp.PixelFormats;
@ -27,7 +28,17 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
/// <summary>
/// Writes a png file.
/// </summary>
Png
Png,
/// <summary>
/// Writes a lossless webp file.
/// </summary>
WebpLossless,
/// <summary>
/// Writes a lossy webp file.
/// </summary>
WebpLossy
}
private static readonly Dictionary<ExifTag, object> TestProfileValues = new Dictionary<ExifTag, object>
@ -44,6 +55,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
[InlineData(TestImageWriteFormat.WebpLossless)]
[InlineData(TestImageWriteFormat.WebpLossy)]
public void Constructor(TestImageWriteFormat imageFormat)
{
Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Calliphora).CreateRgba32Image();
@ -92,6 +105,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
[InlineData(TestImageWriteFormat.WebpLossless)]
[InlineData(TestImageWriteFormat.WebpLossy)]
public void WriteFraction(TestImageWriteFormat imageFormat)
{
using (var memStream = new MemoryStream())
@ -135,6 +150,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
[InlineData(TestImageWriteFormat.WebpLossless)]
[InlineData(TestImageWriteFormat.WebpLossy)]
public void ReadWriteInfinity(TestImageWriteFormat imageFormat)
{
Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
@ -170,6 +187,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
https://exiftool.org/TagNames/EXIF.html */
[InlineData(TestImageWriteFormat.Jpeg, 16)]
[InlineData(TestImageWriteFormat.Png, 16)]
[InlineData(TestImageWriteFormat.WebpLossless, 16)]
public void SetValue(TestImageWriteFormat imageFormat, int expectedProfileValueCount)
{
Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Baseline.Floorplan).CreateRgba32Image();
@ -241,6 +259,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
[InlineData(TestImageWriteFormat.WebpLossless)]
[InlineData(TestImageWriteFormat.WebpLossy)]
public void WriteOnlyExifTags_Works(TestImageWriteFormat imageFormat)
{
// Arrange
@ -327,7 +347,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Fact]
public void ReadWriteLargeProfileJpg()
{
ExifTag<string>[] tags = new[] { ExifTag.Software, ExifTag.Copyright, ExifTag.Model, ExifTag.ImageDescription };
ExifTag<string>[] tags = { ExifTag.Software, ExifTag.Copyright, ExifTag.Model, ExifTag.ImageDescription };
foreach (ExifTag<string> tag in tags)
{
// Arrange
@ -344,7 +364,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
image.Metadata.ExifProfile = expectedProfile;
// Act
using Image<Rgba32> reloadedImage = WriteAndRead(image, TestImageWriteFormat.Jpeg);
Image<Rgba32> reloadedImage = WriteAndRead(image, TestImageWriteFormat.Jpeg);
// Assert
ExifProfile actualProfile = reloadedImage.Metadata.ExifProfile;
@ -366,7 +386,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Fact]
public void ExifTypeUndefined()
{
// This image contains an 802 byte EXIF profile
// This image contains an 802 byte EXIF profile.
// It has a tag with an index offset of 18,481,152 bytes (overrunning the data)
using Image<Rgba32> image = TestFile.Create(TestImages.Jpeg.Progressive.Bad.ExifUndefType).CreateRgba32Image();
Assert.NotNull(image);
@ -409,6 +429,8 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
[Theory]
[InlineData(TestImageWriteFormat.Jpeg)]
[InlineData(TestImageWriteFormat.Png)]
[InlineData(TestImageWriteFormat.WebpLossless)]
[InlineData(TestImageWriteFormat.WebpLossy)]
public void WritingImagePreservesExifProfile(TestImageWriteFormat imageFormat)
{
// Arrange
@ -483,6 +505,10 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
return WriteAndReadJpeg(image);
case TestImageWriteFormat.Png:
return WriteAndReadPng(image);
case TestImageWriteFormat.WebpLossless:
return WriteAndReadWebp(image, lossy: false);
case TestImageWriteFormat.WebpLossy:
return WriteAndReadWebp(image, lossy: true);
default:
throw new ArgumentException("Unexpected test image format, only Jpeg and Png are allowed");
}
@ -512,6 +538,18 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif
}
}
private static Image<Rgba32> WriteAndReadWebp(Image<Rgba32> image, bool lossy)
{
using (var memStream = new MemoryStream())
{
image.SaveAsWebp(memStream, new WebpEncoder() { Lossy = lossy });
image.Dispose();
memStream.Position = 0;
return Image.Load<Rgba32>(memStream, new WebpDecoder());
}
}
private static void TestProfile(ExifProfile profile)
{
Assert.NotNull(profile);

Loading…
Cancel
Save