From 1eb7307d82329b208b5f1edff6d13604c6f1d8ec Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 28 May 2021 04:53:35 +0200 Subject: [PATCH] Add webp EXIF tests --- .../Formats/WebP/BitWriter/Vp8BitWriter.cs | 6 +-- .../Formats/WebP/BitWriter/Vp8LBitWriter.cs | 4 +- .../WebP/Lossless/BackwardReferenceEncoder.cs | 10 ++-- .../Formats/WebP/Lossless/LosslessUtils.cs | 2 +- .../Formats/WebP/Lossless/PredictorEncoder.cs | 20 ++++---- .../Formats/WebP/Lossless/Vp8LEncoder.cs | 2 + .../Formats/WebP/Lossy/Vp8Encoder.cs | 43 ++++++++--------- .../Formats/WebP/WebpDecoderCore.cs | 6 +-- .../Codecs/DecodeTiff.cs | 15 +----- .../Codecs/DecodeWebp.cs | 2 + .../Codecs/EncodeWebp.cs | 2 + .../Formats/WebP/PredictorEncoderTests.cs | 2 +- .../Profiles/Exif/ExifProfileTests.cs | 46 +++++++++++++++++-- 13 files changed, 96 insertions(+), 64 deletions(-) diff --git a/src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs index 106a3e48ef..f717bfe467 100644 --- a/src/ImageSharp/Formats/WebP/BitWriter/Vp8BitWriter.cs +++ b/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) diff --git a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs index 46fb14d382..e3e1a9ddc9 100644 --- a/src/ImageSharp/Formats/WebP/BitWriter/Vp8LBitWriter.cs +++ b/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); } diff --git a/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs index ed4bfe9087..e872eeb633 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/BackwardReferenceEncoder.cs +++ b/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 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 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; diff --git a/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs b/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs index c5ba2c46dc..e14a85ed9a 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/LosslessUtils.cs @@ -31,7 +31,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless /// /// 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. /// diff --git a/src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs index 687dc76ffa..75c182e4d7 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs +++ b/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 maxDiffs = MemoryMarshal.Cast(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; } diff --git a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs index f3c4ad1ca0..3b6ad45ebe 100644 --- a/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/WebP/Lossless/Vp8LEncoder.cs @@ -172,6 +172,8 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless public void Encode(Image image, Stream stream) where TPixel : unmanaged, IPixel { + image.Metadata.SyncProfiles(); + // Write the image size. int width = image.Width; int height = image.Height; diff --git a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs index 40c0cef3a2..c22cd92a51 100644 --- a/src/ImageSharp/Formats/WebP/Lossy/Vp8Encoder.cs +++ b/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(pixelCount); this.U = this.memoryAllocator.Allocate(uvSize); this.V = this.memoryAllocator.Allocate(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 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 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 levels, Span src, Span yuvOut, int mode) { Span 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 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) { diff --git a/src/ImageSharp/Formats/WebP/WebpDecoderCore.cs b/src/ImageSharp/Formats/WebP/WebpDecoderCore.cs index caa64ee611..50d3b48a80 100644 --- a/src/ImageSharp/Formats/WebP/WebpDecoderCore.cs +++ b/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"); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs index e77bb8b3e4..88b6ec26da 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeTiff.cs +++ b/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(this.configuration, ms)) + using (var image = Image.Load(ms)) { return image.Size(); } diff --git a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs index b25da186b5..17cc1865f7 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/DecodeWebp.cs +++ b/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 { diff --git a/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs index b55e630c96..49e1678a20 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/EncodeWebp.cs +++ b/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 { diff --git a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs index 421015d1f9..b5a5df4e8f 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs +++ b/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] diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs index 1f23838ab6..b14938ca8b 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/Exif/ExifProfileTests.cs +++ b/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 /// /// Writes a png file. /// - Png + Png, + + /// + /// Writes a lossless webp file. + /// + WebpLossless, + + /// + /// Writes a lossy webp file. + /// + WebpLossy } private static readonly Dictionary TestProfileValues = new Dictionary @@ -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 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 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 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[] tags = new[] { ExifTag.Software, ExifTag.Copyright, ExifTag.Model, ExifTag.ImageDescription }; + ExifTag[] tags = { ExifTag.Software, ExifTag.Copyright, ExifTag.Model, ExifTag.ImageDescription }; foreach (ExifTag tag in tags) { // Arrange @@ -344,7 +364,7 @@ namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Exif image.Metadata.ExifProfile = expectedProfile; // Act - using Image reloadedImage = WriteAndRead(image, TestImageWriteFormat.Jpeg); + Image 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 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 WriteAndReadWebp(Image image, bool lossy) + { + using (var memStream = new MemoryStream()) + { + image.SaveAsWebp(memStream, new WebpEncoder() { Lossy = lossy }); + image.Dispose(); + + memStream.Position = 0; + return Image.Load(memStream, new WebpDecoder()); + } + } + private static void TestProfile(ExifProfile profile) { Assert.NotNull(profile);