From 3fabb76ab62b4412036de1a687dd38c9bea27928 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 8 Oct 2023 21:32:33 +1000 Subject: [PATCH 001/219] Pool Vp8LHistogram memory. --- .../Webp/Lossless/BackwardReferenceEncoder.cs | 47 +-- .../Formats/Webp/Lossless/CostModel.cs | 16 +- .../Formats/Webp/Lossless/HistogramEncoder.cs | 189 ++++++------ .../Formats/Webp/Lossless/HuffmanUtils.cs | 18 +- .../Formats/Webp/Lossless/PixOrCopy.cs | 2 +- .../Formats/Webp/Lossless/Vp8LBitEntropy.cs | 6 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 117 +++++--- .../Formats/Webp/Lossless/Vp8LHistogram.cs | 273 +++++++++++------- .../Formats/Webp/Lossless/Vp8LHistogramSet.cs | 122 ++++++++ .../Codecs/Webp/EncodeWebp.cs | 13 +- .../Formats/WebP/DominantCostRangeTests.cs | 10 +- .../Formats/WebP/Vp8LHistogramTests.cs | 14 +- 12 files changed, 539 insertions(+), 288 deletions(-) create mode 100644 src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs diff --git a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs index 61133142bf..922ae0193d 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs @@ -50,8 +50,8 @@ internal static class BackwardReferenceEncoder double bitCostBest = -1; int cacheBitsInitial = cacheBits; Vp8LHashChain? hashChainBox = null; - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); for (int lz77Type = 1; lz77TypesToTry > 0; lz77TypesToTry &= ~lz77Type, lz77Type <<= 1) { int cacheBitsTmp = cacheBitsInitial; @@ -76,21 +76,19 @@ internal static class BackwardReferenceEncoder } // Next, try with a color cache and update the references. - cacheBitsTmp = CalculateBestCacheSize(bgra, quality, worst, cacheBitsTmp); + cacheBitsTmp = CalculateBestCacheSize(memoryAllocator, bgra, quality, worst, cacheBitsTmp); if (cacheBitsTmp > 0) { BackwardRefsWithLocalCache(bgra, cacheBitsTmp, worst); } // Keep the best backward references. - var histo = new Vp8LHistogram(worst, cacheBitsTmp); + using Vp8LHistogram histo = new(memoryAllocator, worst, cacheBitsTmp); double bitCost = histo.EstimateBits(stats, bitsEntropy); if (lz77TypeBest == 0 || bitCost < bitCostBest) { - Vp8LBackwardRefs tmp = worst; - worst = best; - best = tmp; + (best, worst) = (worst, best); bitCostBest = bitCost; cacheBits = cacheBitsTmp; lz77TypeBest = lz77Type; @@ -102,7 +100,7 @@ internal static class BackwardReferenceEncoder { Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox!; BackwardReferencesTraceBackwards(width, height, memoryAllocator, bgra, cacheBits, hashChainTmp, best, worst); - var histo = new Vp8LHistogram(worst, cacheBits); + using Vp8LHistogram histo = new(memoryAllocator, worst, cacheBits); double bitCostTrace = histo.EstimateBits(stats, bitsEntropy); if (bitCostTrace < bitCostBest) { @@ -123,7 +121,12 @@ internal static class BackwardReferenceEncoder /// The local color cache is also disabled for the lower (smaller then 25) quality. /// /// Best cache size. - private static int CalculateBestCacheSize(ReadOnlySpan bgra, uint quality, Vp8LBackwardRefs refs, int bestCacheBits) + private static int CalculateBestCacheSize( + MemoryAllocator memoryAllocator, + ReadOnlySpan bgra, + uint quality, + Vp8LBackwardRefs refs, + int bestCacheBits) { int cacheBitsMax = quality <= 25 ? 0 : bestCacheBits; if (cacheBitsMax == 0) @@ -134,11 +137,15 @@ internal static class BackwardReferenceEncoder double entropyMin = MaxEntropy; int pos = 0; - var colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1]; - var histos = new Vp8LHistogram[WebpConstants.MaxColorCacheBits + 1]; + + // TODO: Pass from outer loop and clear. + ColorCache[] colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1]; + + // TODO: Use fixed size. + using Vp8LHistogramSet histos = new(memoryAllocator, WebpConstants.MaxColorCacheBits + 1, 0); for (int i = 0; i <= WebpConstants.MaxColorCacheBits; i++) { - histos[i] = new Vp8LHistogram(paletteCodeBits: i); + histos[i].PaletteCodeBits = i; colorCache[i] = new ColorCache(i); } @@ -149,10 +156,10 @@ internal static class BackwardReferenceEncoder if (v.IsLiteral()) { uint pix = bgra[pos++]; - uint a = (pix >> 24) & 0xff; - uint r = (pix >> 16) & 0xff; - uint g = (pix >> 8) & 0xff; - uint b = (pix >> 0) & 0xff; + int a = (int)(pix >> 24) & 0xff; + int r = (int)(pix >> 16) & 0xff; + int g = (int)(pix >> 8) & 0xff; + int b = (int)(pix >> 0) & 0xff; // The keys of the caches can be derived from the longest one. int key = ColorCache.HashPix(pix, 32 - cacheBitsMax); @@ -218,8 +225,8 @@ internal static class BackwardReferenceEncoder } } - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); for (int i = 0; i <= cacheBitsMax; i++) { double entropy = histos[i].EstimateBits(stats, bitsEntropy); @@ -266,7 +273,7 @@ internal static class BackwardReferenceEncoder int pixCount = xSize * ySize; bool useColorCache = cacheBits > 0; int literalArraySize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (cacheBits > 0 ? 1 << cacheBits : 0); - var costModel = new CostModel(literalArraySize); + CostModel costModel = new(memoryAllocator, literalArraySize); int offsetPrev = -1; int lenPrev = -1; double offsetCost = -1; @@ -280,7 +287,7 @@ internal static class BackwardReferenceEncoder } costModel.Build(xSize, cacheBits, refs); - using var costManager = new CostManager(memoryAllocator, distArrayBuffer, pixCount, costModel); + using CostManager costManager = new(memoryAllocator, distArrayBuffer, pixCount, costModel); Span costManagerCosts = costManager.Costs.GetSpan(); Span distArray = distArrayBuffer.GetSpan(); diff --git a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs index c99e8fe6e2..975fd581d7 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs @@ -1,18 +1,23 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Memory; + namespace SixLabors.ImageSharp.Formats.Webp.Lossless; internal class CostModel { + private readonly MemoryAllocator memoryAllocator; private const int ValuesInBytes = 256; /// /// Initializes a new instance of the class. /// + /// The memory allocator. /// The literal array size. - public CostModel(int literalArraySize) + public CostModel(MemoryAllocator memoryAllocator, int literalArraySize) { + this.memoryAllocator = memoryAllocator; this.Alpha = new double[ValuesInBytes]; this.Red = new double[ValuesInBytes]; this.Blue = new double[ValuesInBytes]; @@ -32,13 +37,12 @@ internal class CostModel public void Build(int xSize, int cacheBits, Vp8LBackwardRefs backwardRefs) { - var histogram = new Vp8LHistogram(cacheBits); - using System.Collections.Generic.List.Enumerator refsEnumerator = backwardRefs.Refs.GetEnumerator(); + using Vp8LHistogram histogram = new(this.memoryAllocator, cacheBits); // The following code is similar to HistogramCreate but converts the distance to plane code. - while (refsEnumerator.MoveNext()) + for (int i = 0; i < backwardRefs.Refs.Count; i++) { - histogram.AddSinglePixOrCopy(refsEnumerator.Current, true, xSize); + histogram.AddSinglePixOrCopy(backwardRefs.Refs[i], true, xSize); } ConvertPopulationCountTableToBitEstimates(histogram.NumCodes(), histogram.Literal, this.Literal); @@ -70,7 +74,7 @@ internal class CostModel public double GetLiteralCost(uint v) => this.Alpha[v >> 24] + this.Red[(v >> 16) & 0xff] + this.Literal[(v >> 8) & 0xff] + this.Blue[v & 0xff]; - private static void ConvertPopulationCountTableToBitEstimates(int numSymbols, uint[] populationCounts, double[] output) + private static void ConvertPopulationCountTableToBitEstimates(int numSymbols, Span populationCounts, double[] output) { uint sum = 0; int nonzeros = 0; diff --git a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs index dd59ed2097..8a0d132063 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs @@ -3,6 +3,7 @@ #nullable disable using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Webp.Lossless; @@ -27,19 +28,28 @@ internal static class HistogramEncoder private const ushort InvalidHistogramSymbol = ushort.MaxValue; - public static void GetHistoImageSymbols(int xSize, int ySize, Vp8LBackwardRefs refs, uint quality, int histoBits, int cacheBits, List imageHisto, Vp8LHistogram tmpHisto, Span histogramSymbols) + public static void GetHistoImageSymbols( + MemoryAllocator memoryAllocator, + int xSize, + int ySize, + Vp8LBackwardRefs refs, + uint quality, + int histoBits, + int cacheBits, + Vp8LHistogramSet imageHisto, + Vp8LHistogram tmpHisto, + Span histogramSymbols) { int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(xSize, histoBits) : 1; int histoYSize = histoBits > 0 ? LosslessUtils.SubSampleSize(ySize, histoBits) : 1; int imageHistoRawSize = histoXSize * histoYSize; - int entropyCombineNumBins = BinSize; + const int entropyCombineNumBins = BinSize; + + // TODO: Allocations! ushort[] mapTmp = new ushort[imageHistoRawSize]; ushort[] clusterMappings = new ushort[imageHistoRawSize]; - var origHisto = new List(imageHistoRawSize); - for (int i = 0; i < imageHistoRawSize; i++) - { - origHisto.Add(new Vp8LHistogram(cacheBits)); - } + + using Vp8LHistogramSet origHisto = new(memoryAllocator, imageHistoRawSize, cacheBits); // Construct the histograms from the backward references. HistogramBuild(xSize, histoBits, refs, origHisto); @@ -61,7 +71,7 @@ internal static class HistogramEncoder OptimizeHistogramSymbols(clusterMappings, numClusters, mapTmp, histogramSymbols); } - float x = quality / 100.0f; + float x = quality / 100F; // Cubic ramp between 1 and MaxHistoGreedy: int thresholdSize = (int)(1 + (x * x * x * (MaxHistoGreedy - 1))); @@ -77,26 +87,25 @@ internal static class HistogramEncoder HistogramRemap(origHisto, imageHisto, histogramSymbols); } - private static void RemoveEmptyHistograms(List histograms) + private static void RemoveEmptyHistograms(Vp8LHistogramSet histograms) { - int size = 0; - for (int i = 0; i < histograms.Count; i++) + for (int i = histograms.Count - 1; i >= 0; i--) { if (histograms[i] == null) { - continue; + histograms.RemoveAt(i); } - - histograms[size++] = histograms[i]; } - - histograms.RemoveRange(size, histograms.Count - size); } /// /// Construct the histograms from the backward references. /// - private static void HistogramBuild(int xSize, int histoBits, Vp8LBackwardRefs backwardRefs, List histograms) + private static void HistogramBuild( + int xSize, + int histoBits, + Vp8LBackwardRefs backwardRefs, + Vp8LHistogramSet histograms) { int x = 0, y = 0; int histoXSize = LosslessUtils.SubSampleSize(xSize, histoBits); @@ -119,10 +128,10 @@ internal static class HistogramEncoder /// Partition histograms to different entropy bins for three dominant (literal, /// red and blue) symbol costs and compute the histogram aggregate bitCost. /// - private static void HistogramAnalyzeEntropyBin(List histograms, ushort[] binMap) + private static void HistogramAnalyzeEntropyBin(Vp8LHistogramSet histograms, ushort[] binMap) { int histoSize = histograms.Count; - var costRange = new DominantCostRange(); + DominantCostRange costRange = new(); // Analyze the dominant (literal, red and blue) entropy costs. for (int i = 0; i < histoSize; i++) @@ -148,25 +157,28 @@ internal static class HistogramEncoder } } - private static int HistogramCopyAndAnalyze(List origHistograms, List histograms, Span histogramSymbols) + private static int HistogramCopyAndAnalyze( + Vp8LHistogramSet origHistograms, + Vp8LHistogramSet histograms, + Span histogramSymbols) { - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); for (int clusterId = 0, i = 0; i < origHistograms.Count; i++) { Vp8LHistogram origHistogram = origHistograms[i]; origHistogram.UpdateHistogramCost(stats, bitsEntropy); // Skip the histogram if it is completely empty, which can happen for tiles with no information (when they are skipped because of LZ77). - if (!origHistogram.IsUsed[0] && !origHistogram.IsUsed[1] && !origHistogram.IsUsed[2] && !origHistogram.IsUsed[3] && !origHistogram.IsUsed[4]) + if (!origHistogram.IsUsed(0) && !origHistogram.IsUsed(1) && !origHistogram.IsUsed(2) && !origHistogram.IsUsed(3) && !origHistogram.IsUsed(4)) { - origHistograms[i] = null; - histograms[i] = null; + origHistograms.DisposeAt(i); + histograms.DisposeAt(i); histogramSymbols[i] = InvalidHistogramSymbol; } else { - histograms[i] = (Vp8LHistogram)origHistogram.DeepClone(); + origHistogram.CopyTo(histograms[i]); histogramSymbols[i] = (ushort)clusterId++; } } @@ -184,7 +196,7 @@ internal static class HistogramEncoder } private static void HistogramCombineEntropyBin( - List histograms, + Vp8LHistogramSet histograms, Span clusters, ushort[] clusterMappings, Vp8LHistogram curCombo, @@ -205,9 +217,9 @@ internal static class HistogramEncoder clusterMappings[idx] = (ushort)idx; } - var indicesToRemove = new List(); - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + List indicesToRemove = new(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); for (int idx = 0; idx < histograms.Count; idx++) { if (histograms[idx] == null) @@ -236,15 +248,13 @@ internal static class HistogramEncoder // histogram pairs. In that case, we fallback to combining // histograms as usual to avoid increasing the header size. bool tryCombine = curCombo.TrivialSymbol != NonTrivialSym || (histograms[idx].TrivialSymbol == NonTrivialSym && histograms[first].TrivialSymbol == NonTrivialSym); - int maxCombineFailures = 32; + const int maxCombineFailures = 32; if (tryCombine || binInfo[binId].NumCombineFailures >= maxCombineFailures) { // Move the (better) merged histogram to its final slot. - Vp8LHistogram tmp = curCombo; - curCombo = histograms[first]; - histograms[first] = tmp; + (histograms[first], curCombo) = (curCombo, histograms[first]); - histograms[idx] = null; + histograms.DisposeAt(idx); indicesToRemove.Add(idx); clusterMappings[clusters[idx]] = clusters[first]; } @@ -256,9 +266,9 @@ internal static class HistogramEncoder } } - foreach (int index in indicesToRemove.OrderByDescending(i => i)) + for (int i = indicesToRemove.Count - 1; i >= 0; i--) { - histograms.RemoveAt(index); + histograms.RemoveAt(indicesToRemove[i]); } } @@ -318,15 +328,15 @@ internal static class HistogramEncoder /// Perform histogram aggregation using a stochastic approach. /// /// true if a greedy approach needs to be performed afterwards, false otherwise. - private static bool HistogramCombineStochastic(List histograms, int minClusterSize) + private static bool HistogramCombineStochastic(Vp8LHistogramSet histograms, int minClusterSize) { uint seed = 1; int triesWithNoSuccess = 0; int numUsed = histograms.Count(h => h != null); int outerIters = numUsed; int numTriesNoSuccess = (int)((uint)outerIters / 2); - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); if (numUsed < minClusterSize) { @@ -335,25 +345,25 @@ internal static class HistogramEncoder // Priority list of histogram pairs. Its size impacts the quality of the compression and the speed: // the smaller the faster but the worse for the compression. - var histoPriorityList = new List(); - int maxSize = 9; + List histoPriorityList = new(); + const int maxSize = 9; // Fill the initial mapping. Span mappings = histograms.Count <= 64 ? stackalloc int[histograms.Count] : new int[histograms.Count]; - for (int j = 0, iter = 0; iter < histograms.Count; iter++) + for (int j = 0, i = 0; i < histograms.Count; i++) { - if (histograms[iter] == null) + if (histograms[i] == null) { continue; } - mappings[j++] = iter; + mappings[j++] = i; } // Collapse similar histograms. - for (int iter = 0; iter < outerIters && numUsed >= minClusterSize && ++triesWithNoSuccess < numTriesNoSuccess; iter++) + for (int i = 0; i < outerIters && numUsed >= minClusterSize && ++triesWithNoSuccess < numTriesNoSuccess; i++) { - double bestCost = histoPriorityList.Count == 0 ? 0.0d : histoPriorityList[0].CostDiff; + double bestCost = histoPriorityList.Count == 0 ? 0D : histoPriorityList[0].CostDiff; int numTries = (int)((uint)numUsed / 2); uint randRange = (uint)((numUsed - 1) * numUsed); @@ -373,7 +383,8 @@ internal static class HistogramEncoder idx2 = mappings[idx2]; // Calculate cost reduction on combination. - double currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost, stats, bitsEntropy); + double currCost = 0; + currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost, stats, bitsEntropy); // Found a better pair? if (currCost < 0) @@ -398,13 +409,13 @@ internal static class HistogramEncoder int mappingIndex = mappings.IndexOf(bestIdx2); Span src = mappings.Slice(mappingIndex + 1, numUsed - mappingIndex - 1); - Span dst = mappings.Slice(mappingIndex); + Span dst = mappings[mappingIndex..]; src.CopyTo(dst); // Merge the histograms and remove bestIdx2 from the list. HistogramAdd(histograms[bestIdx2], histograms[bestIdx1], histograms[bestIdx1]); - histograms.ElementAt(bestIdx1).BitCost = histoPriorityList[0].CostCombo; - histograms[bestIdx2] = null; + histograms[bestIdx1].BitCost = histoPriorityList[0].CostCombo; + histograms.DisposeAt(bestIdx2); numUsed--; for (int j = 0; j < histoPriorityList.Count;) @@ -418,7 +429,7 @@ internal static class HistogramEncoder // check for it all the time nevertheless. if (isIdx1Best && isIdx2Best) { - histoPriorityList[j] = histoPriorityList[histoPriorityList.Count - 1]; + histoPriorityList[j] = histoPriorityList[^1]; histoPriorityList.RemoveAt(histoPriorityList.Count - 1); continue; } @@ -439,18 +450,17 @@ internal static class HistogramEncoder // Make sure the index order is respected. if (p.Idx1 > p.Idx2) { - int tmp = p.Idx2; - p.Idx2 = p.Idx1; - p.Idx1 = tmp; + (p.Idx1, p.Idx2) = (p.Idx2, p.Idx1); } if (doEval) { // Re-evaluate the cost of an updated pair. - HistoListUpdatePair(histograms[p.Idx1], histograms[p.Idx2], stats, bitsEntropy, 0.0d, p); - if (p.CostDiff >= 0.0d) + HistoListUpdatePair(histograms[p.Idx1], histograms[p.Idx2], stats, bitsEntropy, 0D, p); + + if (p.CostDiff >= 0D) { - histoPriorityList[j] = histoPriorityList[histoPriorityList.Count - 1]; + histoPriorityList[j] = histoPriorityList[^1]; histoPriorityList.RemoveAt(histoPriorityList.Count - 1); continue; } @@ -463,20 +473,18 @@ internal static class HistogramEncoder triesWithNoSuccess = 0; } - bool doGreedy = numUsed <= minClusterSize; - - return doGreedy; + return numUsed <= minClusterSize; } - private static void HistogramCombineGreedy(List histograms) + private static void HistogramCombineGreedy(Vp8LHistogramSet histograms) { int histoSize = histograms.Count(h => h != null); // Priority list of histogram pairs. - var histoPriorityList = new List(); + List histoPriorityList = new(); int maxSize = histoSize * histoSize; - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); for (int i = 0; i < histoSize; i++) { @@ -504,16 +512,17 @@ internal static class HistogramEncoder histograms[idx1].BitCost = histoPriorityList[0].CostCombo; // Remove merged histogram. - histograms[idx2] = null; + histograms.DisposeAt(idx2); // Remove pairs intersecting the just combined best pair. + // TODO: Reversing this will avoid the need to remove from the end of the list. for (int i = 0; i < histoPriorityList.Count;) { - HistogramPair p = histoPriorityList.ElementAt(i); + HistogramPair p = histoPriorityList[i]; if (p.Idx1 == idx1 || p.Idx2 == idx1 || p.Idx1 == idx2 || p.Idx2 == idx2) { // Replace item at pos i with the last one and shrinking the list. - histoPriorityList[i] = histoPriorityList[histoPriorityList.Count - 1]; + histoPriorityList[i] = histoPriorityList[^1]; histoPriorityList.RemoveAt(histoPriorityList.Count - 1); } else @@ -536,12 +545,15 @@ internal static class HistogramEncoder } } - private static void HistogramRemap(List input, List output, Span symbols) + private static void HistogramRemap( + Vp8LHistogramSet input, + Vp8LHistogramSet output, + Span symbols) { int inSize = input.Count; int outSize = output.Count; - var stats = new Vp8LStreaks(); - var bitsEntropy = new Vp8LBitEntropy(); + Vp8LStreaks stats = new(); + Vp8LBitEntropy bitsEntropy = new(); if (outSize > 1) { for (int i = 0; i < inSize; i++) @@ -577,11 +589,11 @@ internal static class HistogramEncoder } // Recompute each output. - int paletteCodeBits = output.First().PaletteCodeBits; - output.Clear(); + int paletteCodeBits = output[0].PaletteCodeBits; for (int i = 0; i < outSize; i++) { - output.Add(new Vp8LHistogram(paletteCodeBits)); + output[i].Clear(); + output[i].PaletteCodeBits = paletteCodeBits; } for (int i = 0; i < inSize; i++) @@ -600,20 +612,26 @@ internal static class HistogramEncoder /// Create a pair from indices "idx1" and "idx2" provided its cost is inferior to "threshold", a negative entropy. /// /// The cost of the pair, or 0 if it superior to threshold. - private static double HistoPriorityListPush(List histoList, int maxSize, List histograms, int idx1, int idx2, double threshold, Vp8LStreaks stats, Vp8LBitEntropy bitsEntropy) + private static double HistoPriorityListPush( + List histoList, + int maxSize, + Vp8LHistogramSet histograms, + int idx1, + int idx2, + double threshold, + Vp8LStreaks stats, + Vp8LBitEntropy bitsEntropy) { - var pair = new HistogramPair(); + HistogramPair pair = new(); if (histoList.Count == maxSize) { - return 0.0d; + return 0D; } if (idx1 > idx2) { - int tmp = idx2; - idx2 = idx1; - idx1 = tmp; + (idx1, idx2) = (idx2, idx1); } pair.Idx1 = idx1; @@ -637,9 +655,16 @@ internal static class HistogramEncoder } /// - /// Update the cost diff and combo of a pair of histograms. This needs to be called when the the histograms have been merged with a third one. + /// Update the cost diff and combo of a pair of histograms. This needs to be called when the histograms have been + /// merged with a third one. /// - private static void HistoListUpdatePair(Vp8LHistogram h1, Vp8LHistogram h2, Vp8LStreaks stats, Vp8LBitEntropy bitsEntropy, double threshold, HistogramPair pair) + private static void HistoListUpdatePair( + Vp8LHistogram h1, + Vp8LHistogram h2, + Vp8LStreaks stats, + Vp8LBitEntropy bitsEntropy, + double threshold, + HistogramPair pair) { double sumCost = h1.BitCost + h2.BitCost; pair.CostCombo = 0.0d; diff --git a/src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs b/src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs index 39ad967e38..027d4f7ee9 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/HuffmanUtils.cs @@ -25,7 +25,7 @@ internal static class HuffmanUtils 0x1, 0x9, 0x5, 0xd, 0x3, 0xb, 0x7, 0xf }; - public static void CreateHuffmanTree(uint[] histogram, int treeDepthLimit, bool[] bufRle, Span huffTree, HuffmanTreeCode huffCode) + public static void CreateHuffmanTree(Span histogram, int treeDepthLimit, bool[] bufRle, Span huffTree, HuffmanTreeCode huffCode) { int numSymbols = huffCode.NumSymbols; bufRle.AsSpan().Clear(); @@ -40,7 +40,7 @@ internal static class HuffmanUtils /// Change the population counts in a way that the consequent /// Huffman tree compression, especially its RLE-part, give smaller output. /// - public static void OptimizeHuffmanForRle(int length, bool[] goodForRle, uint[] counts) + public static void OptimizeHuffmanForRle(int length, bool[] goodForRle, Span counts) { // 1) Let's make the Huffman code more compatible with rle encoding. for (; length >= 0; --length) @@ -116,7 +116,7 @@ internal static class HuffmanUtils { // We don't want to change value at counts[i], // that is already belonging to the next stride. Thus - 1. - counts[i - k - 1] = count; + counts[(int)(i - k - 1)] = count; } } @@ -159,7 +159,7 @@ internal static class HuffmanUtils /// The size of the histogram. /// The tree depth limit. /// How many bits are used for the symbol. - public static void GenerateOptimalTree(Span tree, uint[] histogram, int histogramSize, int treeDepthLimit, byte[] bitDepths) + public static void GenerateOptimalTree(Span tree, Span histogram, int histogramSize, int treeDepthLimit, byte[] bitDepths) { uint countMin; int treeSizeOrig = 0; @@ -177,7 +177,7 @@ internal static class HuffmanUtils return; } - Span treePool = tree.Slice(treeSizeOrig); + Span treePool = tree[treeSizeOrig..]; // For block sizes with less than 64k symbols we never need to do a // second iteration of this loop. @@ -202,7 +202,7 @@ internal static class HuffmanUtils } // Build the Huffman tree. - Span treeSlice = tree.Slice(0, treeSize); + Span treeSlice = tree[..treeSize]; treeSlice.Sort(HuffmanTree.Compare); if (treeSize > 1) @@ -357,7 +357,7 @@ internal static class HuffmanUtils // Special case code with only one value. if (offsets[WebpConstants.MaxAllowedCodeLength] == 1) { - var huffmanCode = new HuffmanCode() + HuffmanCode huffmanCode = new() { BitsUsed = 0, Value = (uint)sorted[0] @@ -390,7 +390,7 @@ internal static class HuffmanUtils for (; countsLen > 0; countsLen--) { - var huffmanCode = new HuffmanCode() + HuffmanCode huffmanCode = new() { BitsUsed = len, Value = (uint)sorted[symbol++] @@ -432,7 +432,7 @@ internal static class HuffmanUtils }; } - var huffmanCode = new HuffmanCode + HuffmanCode huffmanCode = new() { BitsUsed = len - rootBits, Value = (uint)sorted[symbol++] diff --git a/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs b/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs index 6a28e5b3fb..cedc809382 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs @@ -37,7 +37,7 @@ internal sealed class PixOrCopy Len = len }; - public uint Literal(int component) => (this.BgraOrDistance >> (component * 8)) & 0xff; + public int Literal(int component) => (int)(this.BgraOrDistance >> (component * 8)) & 0xFF; public uint CacheIdx() => this.BgraOrDistance; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs index 649845b025..330d1c555e 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LBitEntropy.cs @@ -125,7 +125,7 @@ internal class Vp8LBitEntropy /// /// Get the entropy for the distribution 'X'. /// - public void BitsEntropyUnrefined(uint[] x, int length, Vp8LStreaks stats) + public void BitsEntropyUnrefined(Span x, int length, Vp8LStreaks stats) { int i; int iPrev = 0; @@ -147,7 +147,7 @@ internal class Vp8LBitEntropy this.Entropy += LosslessUtils.FastSLog2(this.Sum); } - public void GetCombinedEntropyUnrefined(uint[] x, uint[] y, int length, Vp8LStreaks stats) + public void GetCombinedEntropyUnrefined(Span x, Span y, int length, Vp8LStreaks stats) { int i; int iPrev = 0; @@ -169,7 +169,7 @@ internal class Vp8LBitEntropy this.Entropy += LosslessUtils.FastSLog2(this.Sum); } - public void GetEntropyUnrefined(uint[] x, int length, Vp8LStreaks stats) + public void GetEntropyUnrefined(Span x, int length, Vp8LStreaks stats) { int i; int iPrev = 0; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 1f7c7586eb..10fc8ab804 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -589,15 +589,21 @@ internal class Vp8LEncoder : IDisposable Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0]; this.bitWriter.Reset(bwInit); - Vp8LHistogram tmpHisto = new(cacheBits); - List histogramImage = new(histogramImageXySize); - for (int i = 0; i < histogramImageXySize; i++) - { - histogramImage.Add(new Vp8LHistogram(cacheBits)); - } + using Vp8LHistogram tmpHisto = new(this.memoryAllocator, cacheBits); + using Vp8LHistogramSet histogramImage = new(this.memoryAllocator, histogramImageXySize, cacheBits); // Build histogram image and symbols from backward references. - HistogramEncoder.GetHistoImageSymbols(width, height, refsBest, this.quality, this.HistoBits, cacheBits, histogramImage, tmpHisto, histogramSymbols); + HistogramEncoder.GetHistoImageSymbols( + this.memoryAllocator, + width, + height, + refsBest, + this.quality, + this.HistoBits, + cacheBits, + histogramImage, + tmpHisto, + histogramSymbols); // Create Huffman bit lengths and codes for each histogram image. int histogramImageSize = histogramImage.Count; @@ -678,9 +684,7 @@ internal class Vp8LEncoder : IDisposable // Keep track of the smallest image so far. if (isFirstIteration || (bitWriterBest != null && this.bitWriter.NumBytes() < bitWriterBest.NumBytes())) { - Vp8LBitWriter tmp = this.bitWriter; - this.bitWriter = bitWriterBest; - bitWriterBest = tmp; + (bitWriterBest, this.bitWriter) = (this.bitWriter, bitWriterBest); } isFirstIteration = false; @@ -787,13 +791,8 @@ internal class Vp8LEncoder : IDisposable refsTmp1, refsTmp2); - List histogramImage = new() - { - new(cacheBits) - }; - // Build histogram image and symbols from backward references. - histogramImage[0].StoreRefs(refs); + using Vp8LHistogramSet histogramImage = new(this.memoryAllocator, refs, 1, cacheBits); // Create Huffman bit lengths and codes for each histogram image. GetHuffBitLengthsAndCodes(histogramImage, huffmanCodes); @@ -833,7 +832,7 @@ internal class Vp8LEncoder : IDisposable private void StoreHuffmanCode(Span huffTree, HuffmanTreeToken[] tokens, HuffmanTreeCode huffmanCode) { int count = 0; - Span symbols = this.scratch.Span.Slice(0, 2); + Span symbols = this.scratch.Span[..2]; symbols.Clear(); const int maxBits = 8; const int maxSymbol = 1 << maxBits; @@ -886,6 +885,7 @@ internal class Vp8LEncoder : IDisposable private void StoreFullHuffmanCode(Span huffTree, HuffmanTreeToken[] tokens, HuffmanTreeCode tree) { + // TODO: Allocations. int i; byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes]; short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes]; @@ -996,7 +996,12 @@ internal class Vp8LEncoder : IDisposable } } - private void StoreImageToBitMask(int width, int histoBits, Vp8LBackwardRefs backwardRefs, Span histogramSymbols, HuffmanTreeCode[] huffmanCodes) + private void StoreImageToBitMask( + int width, + int histoBits, + Vp8LBackwardRefs backwardRefs, + Span histogramSymbols, + HuffmanTreeCode[] huffmanCodes) { int histoXSize = histoBits > 0 ? LosslessUtils.SubSampleSize(width, histoBits) : 1; int tileMask = histoBits == 0 ? 0 : -(1 << histoBits); @@ -1008,10 +1013,10 @@ internal class Vp8LEncoder : IDisposable int tileY = y & tileMask; int histogramIx = histogramSymbols[0]; Span codes = huffmanCodes.AsSpan(5 * histogramIx); - using List.Enumerator c = backwardRefs.Refs.GetEnumerator(); - while (c.MoveNext()) + + for (int i = 0; i < backwardRefs.Refs.Count; i++) { - PixOrCopy v = c.Current; + PixOrCopy v = backwardRefs.Refs[i]; if (tileX != (x & tileMask) || tileY != (y & tileMask)) { tileX = x & tileMask; @@ -1024,7 +1029,7 @@ internal class Vp8LEncoder : IDisposable { for (int k = 0; k < 4; k++) { - int code = (int)v.Literal(Order[k]); + int code = v.Literal(Order[k]); this.bitWriter.WriteHuffmanCode(codes[k], code); } } @@ -1379,10 +1384,8 @@ internal class Vp8LEncoder : IDisposable useLut = false; break; } - else - { - buffer[ind] = (uint)j; - } + + buffer[ind] = (uint)j; } if (useLut) @@ -1591,14 +1594,12 @@ internal class Vp8LEncoder : IDisposable } // Swap color(palette[bestIdx], palette[i]); - uint best = palette[bestIdx]; - palette[bestIdx] = palette[i]; - palette[i] = best; + (palette[i], palette[bestIdx]) = (palette[bestIdx], palette[i]); predict = palette[i]; } } - private static void GetHuffBitLengthsAndCodes(List histogramImage, HuffmanTreeCode[] huffmanCodes) + private static void GetHuffBitLengthsAndCodes(Vp8LHistogramSet histogramImage, HuffmanTreeCode[] huffmanCodes) { int maxNumSymbols = 0; @@ -1609,9 +1610,20 @@ internal class Vp8LEncoder : IDisposable int startIdx = 5 * i; for (int k = 0; k < 5; k++) { - int numSymbols = - k == 0 ? histo.NumCodes() : - k == 4 ? WebpConstants.NumDistanceCodes : 256; + int numSymbols; + if (k == 0) + { + numSymbols = histo.NumCodes(); + } + else if (k == 4) + { + numSymbols = WebpConstants.NumDistanceCodes; + } + else + { + numSymbols = 256; + } + huffmanCodes[startIdx + k].NumSymbols = numSymbols; } } @@ -1629,6 +1641,7 @@ internal class Vp8LEncoder : IDisposable } // Create Huffman trees. + // TODO: Allocations. Size here has a max and can be sliced. bool[] bufRle = new bool[maxNumSymbols]; Span huffTree = stackalloc HuffmanTree[3 * maxNumSymbols]; @@ -1682,8 +1695,18 @@ internal class Vp8LEncoder : IDisposable histoBits++; } - return histoBits < WebpConstants.MinHuffmanBits ? WebpConstants.MinHuffmanBits : - histoBits > WebpConstants.MaxHuffmanBits ? WebpConstants.MaxHuffmanBits : histoBits; + if (histoBits < WebpConstants.MinHuffmanBits) + { + return WebpConstants.MinHuffmanBits; + } + else if (histoBits > WebpConstants.MaxHuffmanBits) + { + return WebpConstants.MaxHuffmanBits; + } + else + { + return histoBits; + } } /// @@ -1720,11 +1743,7 @@ internal class Vp8LEncoder : IDisposable [MethodImpl(InliningOptions.ShortMethod)] private static void BitWriterSwap(ref Vp8LBitWriter src, ref Vp8LBitWriter dst) - { - Vp8LBitWriter tmp = src; - src = dst; - dst = tmp; - } + => (dst, src) = (src, dst); /// /// Calculates the bits used for the transformation. @@ -1732,9 +1751,21 @@ internal class Vp8LEncoder : IDisposable [MethodImpl(InliningOptions.ShortMethod)] private static int GetTransformBits(WebpEncodingMethod method, int histoBits) { - int maxTransformBits = (int)method < 4 ? 6 : method > WebpEncodingMethod.Level4 ? 4 : 5; - int res = histoBits > maxTransformBits ? maxTransformBits : histoBits; - return res; + int maxTransformBits; + if ((int)method < 4) + { + maxTransformBits = 6; + } + else if (method > WebpEncodingMethod.Level4) + { + maxTransformBits = 4; + } + else + { + maxTransformBits = 5; + } + + return histoBits > maxTransformBits ? maxTransformBits : histoBits; } [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs index 5ec3f0d53d..07ee88f259 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs @@ -1,63 +1,73 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Buffers; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Webp.Lossless; -internal sealed class Vp8LHistogram : IDeepCloneable +internal sealed class Vp8LHistogram : IDisposable { private const uint NonTrivialSym = 0xffffffff; + private readonly IMemoryOwner buffer; + private const int RedSize = WebpConstants.NumLiteralCodes; + private const int BlueSize = WebpConstants.NumLiteralCodes; + private const int AlphaSize = WebpConstants.NumLiteralCodes; + private const int DistanceSize = WebpConstants.NumDistanceCodes; + public const int LiteralSize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (1 << WebpConstants.MaxColorCacheBits) + 1; + private const int UsedSize = 5; // 5 for literal, red, blue, alpha, distance + public const int BufferSize = RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize + UsedSize; + private readonly bool isSetMember; /// /// Initializes a new instance of the class. /// - /// The histogram to create an instance from. - private Vp8LHistogram(Vp8LHistogram other) - : this(other.PaletteCodeBits) + /// The memory allocator. + /// The backward references to initialize the histogram with. + /// The palette code bits. + public Vp8LHistogram(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int paletteCodeBits) + : this(memoryAllocator, paletteCodeBits) => this.StoreRefs(refs); + + /// + /// Initializes a new instance of the class. + /// + /// The memory allocator. + /// The palette code bits. + public Vp8LHistogram(MemoryAllocator memoryAllocator, int paletteCodeBits) { - other.Red.AsSpan().CopyTo(this.Red); - other.Blue.AsSpan().CopyTo(this.Blue); - other.Alpha.AsSpan().CopyTo(this.Alpha); - other.Literal.AsSpan().CopyTo(this.Literal); - other.Distance.AsSpan().CopyTo(this.Distance); - other.IsUsed.AsSpan().CopyTo(this.IsUsed); - this.LiteralCost = other.LiteralCost; - this.RedCost = other.RedCost; - this.BlueCost = other.BlueCost; - this.BitCost = other.BitCost; - this.TrivialSymbol = other.TrivialSymbol; - this.PaletteCodeBits = other.PaletteCodeBits; + this.buffer = memoryAllocator.Allocate(BufferSize, AllocationOptions.Clean); + this.PaletteCodeBits = paletteCodeBits; } /// /// Initializes a new instance of the class. /// + /// + /// This constructor should be used when the histogram is a member of a . + /// + /// The backing buffer. /// The backward references to initialize the histogram with. /// The palette code bits. - public Vp8LHistogram(Vp8LBackwardRefs refs, int paletteCodeBits) - : this(paletteCodeBits) => this.StoreRefs(refs); + public Vp8LHistogram(IMemoryOwner buffer, Vp8LBackwardRefs refs, int paletteCodeBits) + : this(buffer, paletteCodeBits) => this.StoreRefs(refs); /// /// Initializes a new instance of the class. /// + /// + /// This constructor should be used when the histogram is a member of a . + /// + /// The backing buffer. /// The palette code bits. - public Vp8LHistogram(int paletteCodeBits) + public Vp8LHistogram(IMemoryOwner buffer, int paletteCodeBits) { + this.buffer = buffer; this.PaletteCodeBits = paletteCodeBits; - this.Red = new uint[WebpConstants.NumLiteralCodes + 1]; - this.Blue = new uint[WebpConstants.NumLiteralCodes + 1]; - this.Alpha = new uint[WebpConstants.NumLiteralCodes + 1]; - this.Distance = new uint[WebpConstants.NumDistanceCodes]; - - int literalSize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (1 << WebpConstants.MaxColorCacheBits); - this.Literal = new uint[literalSize + 1]; - - // 5 for literal, red, blue, alpha, distance. - this.IsUsed = new bool[5]; + this.isSetMember = true; } /// @@ -85,22 +95,59 @@ internal sealed class Vp8LHistogram : IDeepCloneable /// public double BlueCost { get; set; } - public uint[] Red { get; } + public Span Red => this.buffer.GetSpan()[..RedSize]; - public uint[] Blue { get; } + public Span Blue => this.buffer.GetSpan().Slice(RedSize, BlueSize); - public uint[] Alpha { get; } + public Span Alpha => this.buffer.GetSpan().Slice(RedSize + BlueSize, AlphaSize); - public uint[] Literal { get; } + public Span Distance => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize, DistanceSize); - public uint[] Distance { get; } + public Span Literal => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize + DistanceSize, LiteralSize); public uint TrivialSymbol { get; set; } - public bool[] IsUsed { get; } + private Span IsUsedSpan => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize, UsedSize); + + public bool IsDisposed { get; set; } - /// - public IDeepCloneable DeepClone() => new Vp8LHistogram(this); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public bool IsUsed(int index) => this.IsUsedSpan[index] == 1u; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void IsUsed(int index, bool value) => this.IsUsedSpan[index] = value ? 1u : 0; + + /// + /// Creates a copy of the given class. + /// + /// The histogram to copy to. + public void CopyTo(Vp8LHistogram other) + { + this.Red.CopyTo(other.Red); + this.Blue.CopyTo(other.Blue); + this.Alpha.CopyTo(other.Alpha); + this.Literal.CopyTo(other.Literal); + this.Distance.CopyTo(other.Distance); + this.IsUsedSpan.CopyTo(other.IsUsedSpan); + + other.LiteralCost = this.LiteralCost; + other.RedCost = this.RedCost; + other.BlueCost = this.BlueCost; + other.BitCost = this.BitCost; + other.TrivialSymbol = this.TrivialSymbol; + other.PaletteCodeBits = this.PaletteCodeBits; + } + + public void Clear() + { + this.buffer.Clear(); + this.PaletteCodeBits = 0; + this.BitCost = 0; + this.LiteralCost = 0; + this.RedCost = 0; + this.BlueCost = 0; + this.TrivialSymbol = 0; + } /// /// Collect all the references into a histogram (without reset). @@ -108,10 +155,9 @@ internal sealed class Vp8LHistogram : IDeepCloneable /// The backward references. public void StoreRefs(Vp8LBackwardRefs refs) { - using List.Enumerator c = refs.Refs.GetEnumerator(); - while (c.MoveNext()) + for (int i = 0; i < refs.Refs.Count; i++) { - this.AddSinglePixOrCopy(c.Current, false); + this.AddSinglePixOrCopy(refs.Refs[i], false); } } @@ -163,12 +209,12 @@ internal sealed class Vp8LHistogram : IDeepCloneable { uint notUsed = 0; return - PopulationCost(this.Literal, this.NumCodes(), ref notUsed, ref this.IsUsed[0], stats, bitsEntropy) - + PopulationCost(this.Red, WebpConstants.NumLiteralCodes, ref notUsed, ref this.IsUsed[1], stats, bitsEntropy) - + PopulationCost(this.Blue, WebpConstants.NumLiteralCodes, ref notUsed, ref this.IsUsed[2], stats, bitsEntropy) - + PopulationCost(this.Alpha, WebpConstants.NumLiteralCodes, ref notUsed, ref this.IsUsed[3], stats, bitsEntropy) - + PopulationCost(this.Distance, WebpConstants.NumDistanceCodes, ref notUsed, ref this.IsUsed[4], stats, bitsEntropy) - + ExtraCost(this.Literal.AsSpan(WebpConstants.NumLiteralCodes), WebpConstants.NumLengthCodes) + this.PopulationCost(this.Literal, this.NumCodes(), ref notUsed, 0, stats, bitsEntropy) + + this.PopulationCost(this.Red, WebpConstants.NumLiteralCodes, ref notUsed, 1, stats, bitsEntropy) + + this.PopulationCost(this.Blue, WebpConstants.NumLiteralCodes, ref notUsed, 2, stats, bitsEntropy) + + this.PopulationCost(this.Alpha, WebpConstants.NumLiteralCodes, ref notUsed, 3, stats, bitsEntropy) + + this.PopulationCost(this.Distance, WebpConstants.NumDistanceCodes, ref notUsed, 4, stats, bitsEntropy) + + ExtraCost(this.Literal[WebpConstants.NumLiteralCodes..], WebpConstants.NumLengthCodes) + ExtraCost(this.Distance, WebpConstants.NumDistanceCodes); } @@ -177,12 +223,12 @@ internal sealed class Vp8LHistogram : IDeepCloneable uint alphaSym = 0, redSym = 0, blueSym = 0; uint notUsed = 0; - double alphaCost = PopulationCost(this.Alpha, WebpConstants.NumLiteralCodes, ref alphaSym, ref this.IsUsed[3], stats, bitsEntropy); - double distanceCost = PopulationCost(this.Distance, WebpConstants.NumDistanceCodes, ref notUsed, ref this.IsUsed[4], stats, bitsEntropy) + ExtraCost(this.Distance, WebpConstants.NumDistanceCodes); + double alphaCost = this.PopulationCost(this.Alpha, WebpConstants.NumLiteralCodes, ref alphaSym, 3, stats, bitsEntropy); + double distanceCost = this.PopulationCost(this.Distance, WebpConstants.NumDistanceCodes, ref notUsed, 4, stats, bitsEntropy) + ExtraCost(this.Distance, WebpConstants.NumDistanceCodes); int numCodes = this.NumCodes(); - this.LiteralCost = PopulationCost(this.Literal, numCodes, ref notUsed, ref this.IsUsed[0], stats, bitsEntropy) + ExtraCost(this.Literal.AsSpan(WebpConstants.NumLiteralCodes), WebpConstants.NumLengthCodes); - this.RedCost = PopulationCost(this.Red, WebpConstants.NumLiteralCodes, ref redSym, ref this.IsUsed[1], stats, bitsEntropy); - this.BlueCost = PopulationCost(this.Blue, WebpConstants.NumLiteralCodes, ref blueSym, ref this.IsUsed[2], stats, bitsEntropy); + this.LiteralCost = this.PopulationCost(this.Literal, numCodes, ref notUsed, 0, stats, bitsEntropy) + ExtraCost(this.Literal[WebpConstants.NumLiteralCodes..], WebpConstants.NumLengthCodes); + this.RedCost = this.PopulationCost(this.Red, WebpConstants.NumLiteralCodes, ref redSym, 1, stats, bitsEntropy); + this.BlueCost = this.PopulationCost(this.Blue, WebpConstants.NumLiteralCodes, ref blueSym, 2, stats, bitsEntropy); this.BitCost = this.LiteralCost + this.RedCost + this.BlueCost + alphaCost + distanceCost; if ((alphaSym | redSym | blueSym) == NonTrivialSym) { @@ -234,7 +280,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable for (int i = 0; i < 5; i++) { - output.IsUsed[i] = this.IsUsed[i] | b.IsUsed[i]; + output.IsUsed(i, this.IsUsed(i) | b.IsUsed(i)); } output.TrivialSymbol = this.TrivialSymbol == b.TrivialSymbol @@ -247,9 +293,9 @@ internal sealed class Vp8LHistogram : IDeepCloneable bool trivialAtEnd = false; cost = costInitial; - cost += GetCombinedEntropy(this.Literal, b.Literal, this.NumCodes(), this.IsUsed[0], b.IsUsed[0], false, stats, bitEntropy); + cost += GetCombinedEntropy(this.Literal, b.Literal, this.NumCodes(), this.IsUsed(0), b.IsUsed(0), false, stats, bitEntropy); - cost += ExtraCostCombined(this.Literal.AsSpan(WebpConstants.NumLiteralCodes), b.Literal.AsSpan(WebpConstants.NumLiteralCodes), WebpConstants.NumLengthCodes); + cost += ExtraCostCombined(this.Literal[WebpConstants.NumLiteralCodes..], b.Literal[WebpConstants.NumLiteralCodes..], WebpConstants.NumLengthCodes); if (cost > costThreshold) { @@ -270,155 +316,158 @@ internal sealed class Vp8LHistogram : IDeepCloneable } } - cost += GetCombinedEntropy(this.Red, b.Red, WebpConstants.NumLiteralCodes, this.IsUsed[1], b.IsUsed[1], trivialAtEnd, stats, bitEntropy); + cost += GetCombinedEntropy(this.Red, b.Red, WebpConstants.NumLiteralCodes, this.IsUsed(1), b.IsUsed(1), trivialAtEnd, stats, bitEntropy); if (cost > costThreshold) { return false; } - cost += GetCombinedEntropy(this.Blue, b.Blue, WebpConstants.NumLiteralCodes, this.IsUsed[2], b.IsUsed[2], trivialAtEnd, stats, bitEntropy); + cost += GetCombinedEntropy(this.Blue, b.Blue, WebpConstants.NumLiteralCodes, this.IsUsed(2), b.IsUsed(2), trivialAtEnd, stats, bitEntropy); if (cost > costThreshold) { return false; } - cost += GetCombinedEntropy(this.Alpha, b.Alpha, WebpConstants.NumLiteralCodes, this.IsUsed[3], b.IsUsed[3], trivialAtEnd, stats, bitEntropy); + cost += GetCombinedEntropy(this.Alpha, b.Alpha, WebpConstants.NumLiteralCodes, this.IsUsed(3), b.IsUsed(3), trivialAtEnd, stats, bitEntropy); if (cost > costThreshold) { return false; } - cost += GetCombinedEntropy(this.Distance, b.Distance, WebpConstants.NumDistanceCodes, this.IsUsed[4], b.IsUsed[4], false, stats, bitEntropy); + cost += GetCombinedEntropy(this.Distance, b.Distance, WebpConstants.NumDistanceCodes, this.IsUsed(4), b.IsUsed(4), false, stats, bitEntropy); if (cost > costThreshold) { return false; } cost += ExtraCostCombined(this.Distance, b.Distance, WebpConstants.NumDistanceCodes); - if (cost > costThreshold) - { - return false; - } - - return true; + return cost <= costThreshold; } private void AddLiteral(Vp8LHistogram b, Vp8LHistogram output, int literalSize) { - if (this.IsUsed[0]) + if (this.IsUsed(0)) { - if (b.IsUsed[0]) + if (b.IsUsed(0)) { AddVector(this.Literal, b.Literal, output.Literal, literalSize); } else { - this.Literal.AsSpan(0, literalSize).CopyTo(output.Literal); + this.Literal[..literalSize].CopyTo(output.Literal); } } - else if (b.IsUsed[0]) + else if (b.IsUsed(0)) { - b.Literal.AsSpan(0, literalSize).CopyTo(output.Literal); + b.Literal[..literalSize].CopyTo(output.Literal); } else { - output.Literal.AsSpan(0, literalSize).Clear(); + output.Literal[..literalSize].Clear(); } } private void AddRed(Vp8LHistogram b, Vp8LHistogram output, int size) { - if (this.IsUsed[1]) + if (this.IsUsed(1)) { - if (b.IsUsed[1]) + if (b.IsUsed(1)) { AddVector(this.Red, b.Red, output.Red, size); } else { - this.Red.AsSpan(0, size).CopyTo(output.Red); + this.Red[..size].CopyTo(output.Red); } } - else if (b.IsUsed[1]) + else if (b.IsUsed(1)) { - b.Red.AsSpan(0, size).CopyTo(output.Red); + b.Red[..size].CopyTo(output.Red); } else { - output.Red.AsSpan(0, size).Clear(); + output.Red[..size].Clear(); } } private void AddBlue(Vp8LHistogram b, Vp8LHistogram output, int size) { - if (this.IsUsed[2]) + if (this.IsUsed(2)) { - if (b.IsUsed[2]) + if (b.IsUsed(2)) { AddVector(this.Blue, b.Blue, output.Blue, size); } else { - this.Blue.AsSpan(0, size).CopyTo(output.Blue); + this.Blue[..size].CopyTo(output.Blue); } } - else if (b.IsUsed[2]) + else if (b.IsUsed(2)) { - b.Blue.AsSpan(0, size).CopyTo(output.Blue); + b.Blue[..size].CopyTo(output.Blue); } else { - output.Blue.AsSpan(0, size).Clear(); + output.Blue[..size].Clear(); } } private void AddAlpha(Vp8LHistogram b, Vp8LHistogram output, int size) { - if (this.IsUsed[3]) + if (this.IsUsed(3)) { - if (b.IsUsed[3]) + if (b.IsUsed(3)) { AddVector(this.Alpha, b.Alpha, output.Alpha, size); } else { - this.Alpha.AsSpan(0, size).CopyTo(output.Alpha); + this.Alpha[..size].CopyTo(output.Alpha); } } - else if (b.IsUsed[3]) + else if (b.IsUsed(3)) { - b.Alpha.AsSpan(0, size).CopyTo(output.Alpha); + b.Alpha[..size].CopyTo(output.Alpha); } else { - output.Alpha.AsSpan(0, size).Clear(); + output.Alpha[..size].Clear(); } } private void AddDistance(Vp8LHistogram b, Vp8LHistogram output, int size) { - if (this.IsUsed[4]) + if (this.IsUsed(4)) { - if (b.IsUsed[4]) + if (b.IsUsed(4)) { AddVector(this.Distance, b.Distance, output.Distance, size); } else { - this.Distance.AsSpan(0, size).CopyTo(output.Distance); + this.Distance[..size].CopyTo(output.Distance); } } - else if (b.IsUsed[4]) + else if (b.IsUsed(4)) { - b.Distance.AsSpan(0, size).CopyTo(output.Distance); + b.Distance[..size].CopyTo(output.Distance); } else { - output.Distance.AsSpan(0, size).Clear(); + output.Distance[..size].Clear(); } } - private static double GetCombinedEntropy(uint[] x, uint[] y, int length, bool isXUsed, bool isYUsed, bool trivialAtEnd, Vp8LStreaks stats, Vp8LBitEntropy bitEntropy) + private static double GetCombinedEntropy( + Span x, + Span y, + int length, + bool isXUsed, + bool isYUsed, + bool trivialAtEnd, + Vp8LStreaks stats, + Vp8LBitEntropy bitEntropy) { stats.Clear(); bitEntropy.Init(); @@ -450,18 +499,15 @@ internal sealed class Vp8LHistogram : IDeepCloneable bitEntropy.GetEntropyUnrefined(x, length, stats); } } + else if (isYUsed) + { + bitEntropy.GetEntropyUnrefined(y, length, stats); + } else { - if (isYUsed) - { - bitEntropy.GetEntropyUnrefined(y, length, stats); - } - else - { - stats.Counts[0] = 1; - stats.Streaks[0][length > 3 ? 1 : 0] = length; - bitEntropy.Init(); - } + stats.Counts[0] = 1; + stats.Streaks[0][length > 3 ? 1 : 0] = length; + bitEntropy.Init(); } return bitEntropy.BitsEntropyRefine() + stats.FinalHuffmanCost(); @@ -482,7 +528,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable /// /// Get the symbol entropy for the distribution 'population'. /// - private static double PopulationCost(uint[] population, int length, ref uint trivialSym, ref bool isUsed, Vp8LStreaks stats, Vp8LBitEntropy bitEntropy) + private double PopulationCost(Span population, int length, ref uint trivialSym, int isUsedIndex, Vp8LStreaks stats, Vp8LBitEntropy bitEntropy) { bitEntropy.Init(); stats.Clear(); @@ -491,7 +537,7 @@ internal sealed class Vp8LHistogram : IDeepCloneable trivialSym = (bitEntropy.NoneZeros == 1) ? bitEntropy.NoneZeroCode : NonTrivialSym; // The histogram is used if there is at least one non-zero streak. - isUsed = stats.Streaks[1][0] != 0 || stats.Streaks[1][1] != 0; + this.IsUsed(isUsedIndex, stats.Streaks[1][0] != 0 || stats.Streaks[1][1] != 0); return bitEntropy.BitsEntropyRefine() + stats.FinalHuffmanCost(); } @@ -556,4 +602,17 @@ internal sealed class Vp8LHistogram : IDeepCloneable } } } + + public void Dispose() + { + if (!this.IsDisposed) + { + if (!this.isSetMember) + { + this.buffer.Dispose(); + } + + this.IsDisposed = true; + } + } } diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs new file mode 100644 index 0000000000..0044c7376e --- /dev/null +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs @@ -0,0 +1,122 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +#nullable disable + +using System.Buffers; +using System.Collections; +using System.Diagnostics; +using SixLabors.ImageSharp.Memory; + +namespace SixLabors.ImageSharp.Formats.Webp.Lossless; + +internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable +{ + private readonly IMemoryOwner buffer; + private readonly List items; + private bool isDisposed; + + public Vp8LHistogramSet(MemoryAllocator memoryAllocator, int capacity, int cacheBits) + { + this.buffer = memoryAllocator.Allocate(Vp8LHistogram.BufferSize * capacity, AllocationOptions.Clean); + + this.items = new List(capacity); + for (int i = 0; i < capacity; i++) + { + SetItemMemoryOwner owner = new(this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize)); + this.items.Add(new Vp8LHistogram(owner, cacheBits)); + } + } + + public Vp8LHistogramSet(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int capacity, int cacheBits) + { + this.buffer = memoryAllocator.Allocate(Vp8LHistogram.BufferSize * capacity, AllocationOptions.Clean); + + this.items = new List(capacity); + for (int i = 0; i < capacity; i++) + { + SetItemMemoryOwner owner = new(this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize)); + this.items.Add(new Vp8LHistogram(owner, refs, cacheBits)); + } + } + + public Vp8LHistogramSet(int capacity) => this.items = new(capacity); + + public Vp8LHistogramSet() => this.items = new(); + + public int Count => this.items.Count; + + public Vp8LHistogram this[int index] + { + get => this.items[index]; + + // TODO: Should we check and throw for null? + set => this.items[index] = value; + } + + public void DisposeAt(int index) + { + this.CheckDisposed(); + + Vp8LHistogram item = this.items[index]; + item?.Dispose(); + this.items[index] = null; + } + + public void RemoveAt(int index) + { + this.CheckDisposed(); + + Vp8LHistogram item = this.items[index]; + item?.Dispose(); + this.items.RemoveAt(index); +#pragma warning disable IDE0059 // Unnecessary assignment of a value + item = null; +#pragma warning restore IDE0059 // Unnecessary assignment of a value + } + + public void Dispose() + { + if (this.isDisposed) + { + return; + } + + this.buffer.Dispose(); + + foreach (Vp8LHistogram item in this.items) + { + item?.Dispose(); + } + + this.items.Clear(); + this.isDisposed = true; + } + + public IEnumerator GetEnumerator() => ((IEnumerable)this.items).GetEnumerator(); + + IEnumerator IEnumerable.GetEnumerator() => ((IEnumerable)this.items).GetEnumerator(); + + [Conditional("DEBUG")] + private void CheckDisposed() + { + if (this.isDisposed) + { + ThrowDisposed(); + } + } + + private static void ThrowDisposed() => throw new ObjectDisposedException(nameof(Vp8LHistogramSet)); + + private sealed class SetItemMemoryOwner : IMemoryOwner + { + public SetItemMemoryOwner(Memory memory) => this.Memory = memory; + + public Memory Memory { get; } + + public void Dispose() + { + // Do nothing, the underlying memory is owned by the parent set. + } + } +} diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs index 65b4ae2c31..c5fa8d03da 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs @@ -43,9 +43,9 @@ public class EncodeWebp [Benchmark(Description = "Magick Webp Lossy")] public void MagickWebpLossy() { - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); - var defines = new WebPWriteDefines + WebPWriteDefines defines = new() { Lossless = false, Method = 4, @@ -65,7 +65,7 @@ public class EncodeWebp [Benchmark(Description = "ImageSharp Webp Lossy")] public void ImageSharpWebpLossy() { - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); this.webp.Save(memoryStream, new WebpEncoder() { FileFormat = WebpFileFormatType.Lossy, @@ -80,8 +80,8 @@ public class EncodeWebp [Benchmark(Baseline = true, Description = "Magick Webp Lossless")] public void MagickWebpLossless() { - using var memoryStream = new MemoryStream(); - var defines = new WebPWriteDefines + using MemoryStream memoryStream = new(); + WebPWriteDefines defines = new() { Lossless = true, Method = 4, @@ -97,12 +97,13 @@ public class EncodeWebp [Benchmark(Description = "ImageSharp Webp Lossless")] public void ImageSharpWebpLossless() { - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); this.webp.Save(memoryStream, new WebpEncoder() { FileFormat = WebpFileFormatType.Lossless, Method = WebpEncodingMethod.Level4, NearLossless = false, + Quality = 75, // This is equal to exact = false in libwebp, which is the default. TransparentColorMode = WebpTransparentColorMode.Clear diff --git a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs index 11c4bb62e7..80b41c5e4e 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs @@ -11,7 +11,7 @@ public class DominantCostRangeTests [Fact] public void DominantCost_Constructor() { - var dominantCostRange = new DominantCostRange(); + DominantCostRange dominantCostRange = new(); Assert.Equal(0, dominantCostRange.LiteralMax); Assert.Equal(double.MaxValue, dominantCostRange.LiteralMin); Assert.Equal(0, dominantCostRange.RedMax); @@ -24,8 +24,8 @@ public class DominantCostRangeTests public void UpdateDominantCostRange_Works() { // arrange - var dominantCostRange = new DominantCostRange(); - var histogram = new Vp8LHistogram(10) + DominantCostRange dominantCostRange = new(); + using Vp8LHistogram histogram = new(Configuration.Default.MemoryAllocator, 10) { LiteralCost = 1.0d, RedCost = 2.0d, @@ -50,7 +50,7 @@ public class DominantCostRangeTests public void GetHistoBinIndex_Works(int partitions, int expectedIndex) { // arrange - var dominantCostRange = new DominantCostRange() + DominantCostRange dominantCostRange = new() { BlueMax = 253.4625, BlueMin = 109.0, @@ -59,7 +59,7 @@ public class DominantCostRangeTests RedMax = 191.0, RedMin = 109.0 }; - var histogram = new Vp8LHistogram(6) + using Vp8LHistogram histogram = new(Configuration.Default.MemoryAllocator, 6) { LiteralCost = 247.0d, RedCost = 112.0d, diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs index 39c3c89550..755b735452 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Webp.Lossless; +using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Tests.TestUtilities; namespace SixLabors.ImageSharp.Tests.Formats.Webp; @@ -65,7 +66,7 @@ public class Vp8LHistogramTests // All remaining values are expected to be zero. literals.AsSpan().CopyTo(expectedLiterals); - var backwardRefs = new Vp8LBackwardRefs(pixelData.Length); + Vp8LBackwardRefs backwardRefs = new(pixelData.Length); for (int i = 0; i < pixelData.Length; i++) { backwardRefs.Add(new PixOrCopy() @@ -76,15 +77,16 @@ public class Vp8LHistogramTests }); } - var histogram0 = new Vp8LHistogram(backwardRefs, 3); - var histogram1 = new Vp8LHistogram(backwardRefs, 3); + MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; + using Vp8LHistogram histogram0 = new(memoryAllocator, backwardRefs, 3); + using Vp8LHistogram histogram1 = new(memoryAllocator, backwardRefs, 3); for (int i = 0; i < 5; i++) { - histogram0.IsUsed[i] = true; - histogram1.IsUsed[i] = true; + histogram0.IsUsed(i, true); + histogram1.IsUsed(i, true); } - var output = new Vp8LHistogram(3); + using Vp8LHistogram output = new(memoryAllocator, 3); // act histogram0.Add(histogram1, output); From 63829e84377dcfd00b3ee43347d297977a355fd9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 8 Oct 2023 22:18:48 +1000 Subject: [PATCH 002/219] Remove more allocations and add tasks. --- .../Webp/Lossless/BackwardReferenceEncoder.cs | 23 ++++++++----------- .../Formats/Webp/Lossless/HistogramEncoder.cs | 23 +++++++++---------- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 7 +++--- 3 files changed, 25 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs index 922ae0193d..a56fc0faca 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs @@ -52,6 +52,8 @@ internal static class BackwardReferenceEncoder Vp8LHashChain? hashChainBox = null; Vp8LStreaks stats = new(); Vp8LBitEntropy bitsEntropy = new(); + + ColorCache[] colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1]; for (int lz77Type = 1; lz77TypesToTry > 0; lz77TypesToTry &= ~lz77Type, lz77Type <<= 1) { int cacheBitsTmp = cacheBitsInitial; @@ -76,7 +78,7 @@ internal static class BackwardReferenceEncoder } // Next, try with a color cache and update the references. - cacheBitsTmp = CalculateBestCacheSize(memoryAllocator, bgra, quality, worst, cacheBitsTmp); + cacheBitsTmp = CalculateBestCacheSize(memoryAllocator, colorCache, bgra, quality, worst, cacheBitsTmp); if (cacheBitsTmp > 0) { BackwardRefsWithLocalCache(bgra, cacheBitsTmp, worst); @@ -123,6 +125,7 @@ internal static class BackwardReferenceEncoder /// Best cache size. private static int CalculateBestCacheSize( MemoryAllocator memoryAllocator, + Span colorCache, ReadOnlySpan bgra, uint quality, Vp8LBackwardRefs refs, @@ -138,12 +141,8 @@ internal static class BackwardReferenceEncoder double entropyMin = MaxEntropy; int pos = 0; - // TODO: Pass from outer loop and clear. - ColorCache[] colorCache = new ColorCache[WebpConstants.MaxColorCacheBits + 1]; - - // TODO: Use fixed size. - using Vp8LHistogramSet histos = new(memoryAllocator, WebpConstants.MaxColorCacheBits + 1, 0); - for (int i = 0; i <= WebpConstants.MaxColorCacheBits; i++) + using Vp8LHistogramSet histos = new(memoryAllocator, colorCache.Length, 0); + for (int i = 0; i < colorCache.Length; i++) { histos[i].PaletteCodeBits = i; colorCache[i] = new ColorCache(i); @@ -448,12 +447,12 @@ internal static class BackwardReferenceEncoder int ix = useColorCache ? colorCache!.Contains(color) : -1; if (ix >= 0) { - double mul0 = 0.68; + const double mul0 = 0.68; costVal += costModel.GetCacheCost((uint)ix) * mul0; } else { - double mul1 = 0.82; + const double mul1 = 0.82; if (useColorCache) { colorCache!.Insert(color); @@ -700,10 +699,8 @@ internal static class BackwardReferenceEncoder bestLength = MaxLength; break; } - else - { - bestLength = currLength; - } + + bestLength = currLength; } } } diff --git a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs index 8a0d132063..cce0356176 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. #nullable disable +using System.Buffers; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory; @@ -45,9 +46,9 @@ internal static class HistogramEncoder int imageHistoRawSize = histoXSize * histoYSize; const int entropyCombineNumBins = BinSize; - // TODO: Allocations! - ushort[] mapTmp = new ushort[imageHistoRawSize]; - ushort[] clusterMappings = new ushort[imageHistoRawSize]; + using IMemoryOwner tmp = memoryAllocator.Allocate(imageHistoRawSize * 2, AllocationOptions.Clean); + Span mapTmp = tmp.Slice(0, imageHistoRawSize); + Span clusterMappings = tmp.Slice(imageHistoRawSize, imageHistoRawSize); using Vp8LHistogramSet origHisto = new(memoryAllocator, imageHistoRawSize, cacheBits); @@ -60,13 +61,12 @@ internal static class HistogramEncoder bool entropyCombine = numUsed > entropyCombineNumBins * 2 && quality < 100; if (entropyCombine) { - ushort[] binMap = mapTmp; int numClusters = numUsed; double combineCostFactor = GetCombineCostFactor(imageHistoRawSize, quality); - HistogramAnalyzeEntropyBin(imageHisto, binMap); + HistogramAnalyzeEntropyBin(imageHisto, mapTmp); // Collapse histograms with similar entropy. - HistogramCombineEntropyBin(imageHisto, histogramSymbols, clusterMappings, tmpHisto, binMap, entropyCombineNumBins, combineCostFactor); + HistogramCombineEntropyBin(imageHisto, histogramSymbols, clusterMappings, tmpHisto, mapTmp, entropyCombineNumBins, combineCostFactor); OptimizeHistogramSymbols(clusterMappings, numClusters, mapTmp, histogramSymbols); } @@ -128,7 +128,7 @@ internal static class HistogramEncoder /// Partition histograms to different entropy bins for three dominant (literal, /// red and blue) symbol costs and compute the histogram aggregate bitCost. /// - private static void HistogramAnalyzeEntropyBin(Vp8LHistogramSet histograms, ushort[] binMap) + private static void HistogramAnalyzeEntropyBin(Vp8LHistogramSet histograms, Span binMap) { int histoSize = histograms.Count; DominantCostRange costRange = new(); @@ -198,9 +198,9 @@ internal static class HistogramEncoder private static void HistogramCombineEntropyBin( Vp8LHistogramSet histograms, Span clusters, - ushort[] clusterMappings, + Span clusterMappings, Vp8LHistogram curCombo, - ushort[] binMap, + ReadOnlySpan binMap, int numBins, double combineCostFactor) { @@ -276,7 +276,7 @@ internal static class HistogramEncoder /// Given a Histogram set, the mapping of clusters 'clusterMapping' and the /// current assignment of the cells in 'symbols', merge the clusters and assign the smallest possible clusters values. /// - private static void OptimizeHistogramSymbols(ushort[] clusterMappings, int numClusters, ushort[] clusterMappingsTmp, Span symbols) + private static void OptimizeHistogramSymbols(Span clusterMappings, int numClusters, Span clusterMappingsTmp, Span symbols) { bool doContinue = true; @@ -303,7 +303,7 @@ internal static class HistogramEncoder // Create a mapping from a cluster id to its minimal version. int clusterMax = 0; - clusterMappingsTmp.AsSpan().Clear(); + clusterMappingsTmp.Clear(); // Re-map the ids. for (int i = 0; i < symbols.Length; i++) @@ -515,7 +515,6 @@ internal static class HistogramEncoder histograms.DisposeAt(idx2); // Remove pairs intersecting the just combined best pair. - // TODO: Reversing this will avoid the need to remove from the end of the list. for (int i = 0; i < histoPriorityList.Count;) { HistogramPair p = histoPriorityList[i]; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 10fc8ab804..d570bd448a 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -885,7 +885,7 @@ internal class Vp8LEncoder : IDisposable private void StoreFullHuffmanCode(Span huffTree, HuffmanTreeToken[] tokens, HuffmanTreeCode tree) { - // TODO: Allocations. + // TODO: Allocations. This method is called in a loop. int i; byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes]; short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes]; @@ -1628,6 +1628,7 @@ internal class Vp8LEncoder : IDisposable } } + // TODO: Allocations. int end = 5 * histogramImage.Count; for (int i = 0; i < end; i++) { @@ -1641,9 +1642,9 @@ internal class Vp8LEncoder : IDisposable } // Create Huffman trees. - // TODO: Allocations. Size here has a max and can be sliced. + // TODO: Allocations. bool[] bufRle = new bool[maxNumSymbols]; - Span huffTree = stackalloc HuffmanTree[3 * maxNumSymbols]; + HuffmanTree[] huffTree = new HuffmanTree[3 * maxNumSymbols]; for (int i = 0; i < histogramImage.Count; i++) { From bea65987a067c0f1f9efa8bc5953d86db2a21976 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Mon, 9 Oct 2023 00:35:51 +0200 Subject: [PATCH 003/219] use pinned buffers in Vp8LHistogram --- .../Webp/Lossless/BackwardReferenceEncoder.cs | 4 +- .../Formats/Webp/Lossless/CostModel.cs | 2 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 2 +- .../Formats/Webp/Lossless/Vp8LHistogram.cs | 92 +++++++++++-------- .../Formats/Webp/Lossless/Vp8LHistogramSet.cs | 24 ++--- .../Formats/WebP/DominantCostRangeTests.cs | 23 ++--- .../Formats/WebP/Vp8LHistogramTests.cs | 6 +- 7 files changed, 77 insertions(+), 76 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs index a56fc0faca..185ba1e346 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs @@ -85,7 +85,7 @@ internal static class BackwardReferenceEncoder } // Keep the best backward references. - using Vp8LHistogram histo = new(memoryAllocator, worst, cacheBitsTmp); + using Vp8LHistogram histo = Vp8LHistogram.Create(memoryAllocator, worst, cacheBitsTmp); double bitCost = histo.EstimateBits(stats, bitsEntropy); if (lz77TypeBest == 0 || bitCost < bitCostBest) @@ -102,7 +102,7 @@ internal static class BackwardReferenceEncoder { Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox!; BackwardReferencesTraceBackwards(width, height, memoryAllocator, bgra, cacheBits, hashChainTmp, best, worst); - using Vp8LHistogram histo = new(memoryAllocator, worst, cacheBits); + using Vp8LHistogram histo = Vp8LHistogram.Create(memoryAllocator, worst, cacheBits); double bitCostTrace = histo.EstimateBits(stats, bitsEntropy); if (bitCostTrace < bitCostBest) { diff --git a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs index 975fd581d7..94d60b4ee3 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs @@ -37,7 +37,7 @@ internal class CostModel public void Build(int xSize, int cacheBits, Vp8LBackwardRefs backwardRefs) { - using Vp8LHistogram histogram = new(this.memoryAllocator, cacheBits); + using Vp8LHistogram histogram = Vp8LHistogram.Create(this.memoryAllocator, cacheBits); // The following code is similar to HistogramCreate but converts the distance to plane code. for (int i = 0; i < backwardRefs.Refs.Count; i++) diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index d570bd448a..532e75359d 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -589,7 +589,7 @@ internal class Vp8LEncoder : IDisposable Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0]; this.bitWriter.Reset(bwInit); - using Vp8LHistogram tmpHisto = new(this.memoryAllocator, cacheBits); + using Vp8LHistogram tmpHisto = Vp8LHistogram.Create(this.memoryAllocator, cacheBits); using Vp8LHistogramSet histogramImage = new(this.memoryAllocator, histogramImageXySize, cacheBits); // Build histogram image and symbols from backward references. diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs index 07ee88f259..023f1c943b 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs @@ -10,10 +10,20 @@ using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Webp.Lossless; -internal sealed class Vp8LHistogram : IDisposable +internal sealed unsafe class Vp8LHistogram : IDisposable { private const uint NonTrivialSym = 0xffffffff; - private readonly IMemoryOwner buffer; + private readonly IMemoryOwner? bufferOwner; + private readonly Memory buffer; + private readonly MemoryHandle bufferHandle; + + private readonly uint* red; + private readonly uint* blue; + private readonly uint* alpha; + private readonly uint* distance; + private readonly uint* literal; + private readonly uint* isUsed; + private const int RedSize = WebpConstants.NumLiteralCodes; private const int BlueSize = WebpConstants.NumLiteralCodes; private const int AlphaSize = WebpConstants.NumLiteralCodes; @@ -21,27 +31,6 @@ internal sealed class Vp8LHistogram : IDisposable public const int LiteralSize = WebpConstants.NumLiteralCodes + WebpConstants.NumLengthCodes + (1 << WebpConstants.MaxColorCacheBits) + 1; private const int UsedSize = 5; // 5 for literal, red, blue, alpha, distance public const int BufferSize = RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize + UsedSize; - private readonly bool isSetMember; - - /// - /// Initializes a new instance of the class. - /// - /// The memory allocator. - /// The backward references to initialize the histogram with. - /// The palette code bits. - public Vp8LHistogram(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int paletteCodeBits) - : this(memoryAllocator, paletteCodeBits) => this.StoreRefs(refs); - - /// - /// Initializes a new instance of the class. - /// - /// The memory allocator. - /// The palette code bits. - public Vp8LHistogram(MemoryAllocator memoryAllocator, int paletteCodeBits) - { - this.buffer = memoryAllocator.Allocate(BufferSize, AllocationOptions.Clean); - this.PaletteCodeBits = paletteCodeBits; - } /// /// Initializes a new instance of the class. @@ -52,7 +41,7 @@ internal sealed class Vp8LHistogram : IDisposable /// The backing buffer. /// The backward references to initialize the histogram with. /// The palette code bits. - public Vp8LHistogram(IMemoryOwner buffer, Vp8LBackwardRefs refs, int paletteCodeBits) + public Vp8LHistogram(Memory buffer, Vp8LBackwardRefs refs, int paletteCodeBits) : this(buffer, paletteCodeBits) => this.StoreRefs(refs); /// @@ -63,11 +52,20 @@ internal sealed class Vp8LHistogram : IDisposable /// /// The backing buffer. /// The palette code bits. - public Vp8LHistogram(IMemoryOwner buffer, int paletteCodeBits) + /// Optional buffer owner to dispose. + public Vp8LHistogram(Memory buffer, int paletteCodeBits, IMemoryOwner? bufferOwner = null) { + this.bufferOwner = bufferOwner; this.buffer = buffer; + this.bufferHandle = this.buffer.Pin(); this.PaletteCodeBits = paletteCodeBits; - this.isSetMember = true; + + this.red = (uint*)this.bufferHandle.Pointer; + this.blue = this.red + RedSize; + this.alpha = this.blue + BlueSize; + this.distance = this.alpha + AlphaSize; + this.literal = this.distance + DistanceSize; + this.isUsed = this.literal + LiteralSize; } /// @@ -95,22 +93,43 @@ internal sealed class Vp8LHistogram : IDisposable /// public double BlueCost { get; set; } - public Span Red => this.buffer.GetSpan()[..RedSize]; + public Span Red => new(this.red, RedSize); - public Span Blue => this.buffer.GetSpan().Slice(RedSize, BlueSize); + public Span Blue => new(this.blue, BlueSize); - public Span Alpha => this.buffer.GetSpan().Slice(RedSize + BlueSize, AlphaSize); + public Span Alpha => new(this.alpha, AlphaSize); - public Span Distance => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize, DistanceSize); + public Span Distance => new(this.distance, DistanceSize); - public Span Literal => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize + DistanceSize, LiteralSize); + public Span Literal => new(this.literal, LiteralSize); public uint TrivialSymbol { get; set; } - private Span IsUsedSpan => this.buffer.GetSpan().Slice(RedSize + BlueSize + AlphaSize + DistanceSize + LiteralSize, UsedSize); + private Span IsUsedSpan => new(this.isUsed, UsedSize); + + private Span TotalSpan => new(this.red, BufferSize); public bool IsDisposed { get; set; } + /// + /// Creates an that is not a member of a . + /// + public static Vp8LHistogram Create(MemoryAllocator memoryAllocator, int paletteCodeBits) + { + IMemoryOwner bufferOwner = memoryAllocator.Allocate(BufferSize, AllocationOptions.Clean); + return new Vp8LHistogram(bufferOwner.Memory, paletteCodeBits, bufferOwner); + } + + /// + /// Creates an that is not a member of a . + /// + public static Vp8LHistogram Create(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int paletteCodeBits) + { + Vp8LHistogram histogram = Create(memoryAllocator, paletteCodeBits); + histogram.StoreRefs(refs); + return histogram; + } + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsUsed(int index) => this.IsUsedSpan[index] == 1u; @@ -140,7 +159,7 @@ internal sealed class Vp8LHistogram : IDisposable public void Clear() { - this.buffer.Clear(); + this.TotalSpan.Clear(); this.PaletteCodeBits = 0; this.BitCost = 0; this.LiteralCost = 0; @@ -607,11 +626,8 @@ internal sealed class Vp8LHistogram : IDisposable { if (!this.IsDisposed) { - if (!this.isSetMember) - { - this.buffer.Dispose(); - } - + this.bufferHandle.Dispose(); + this.bufferOwner?.Dispose(); this.IsDisposed = true; } } diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs index 0044c7376e..b7b884dfc8 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs @@ -23,8 +23,8 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable this.items = new List(capacity); for (int i = 0; i < capacity; i++) { - SetItemMemoryOwner owner = new(this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize)); - this.items.Add(new Vp8LHistogram(owner, cacheBits)); + Memory subBuffer = this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize); + this.items.Add(new Vp8LHistogram(subBuffer, cacheBits)); } } @@ -35,8 +35,8 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable this.items = new List(capacity); for (int i = 0; i < capacity; i++) { - SetItemMemoryOwner owner = new(this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize)); - this.items.Add(new Vp8LHistogram(owner, refs, cacheBits)); + Memory subBuffer = this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize); + this.items.Add(new Vp8LHistogram(subBuffer, refs, cacheBits)); } } @@ -82,13 +82,13 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable return; } - this.buffer.Dispose(); - foreach (Vp8LHistogram item in this.items) { + // First, make sure to unpin individual sub buffers. item?.Dispose(); } + this.buffer.Dispose(); this.items.Clear(); this.isDisposed = true; } @@ -107,16 +107,4 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable } private static void ThrowDisposed() => throw new ObjectDisposedException(nameof(Vp8LHistogramSet)); - - private sealed class SetItemMemoryOwner : IMemoryOwner - { - public SetItemMemoryOwner(Memory memory) => this.Memory = memory; - - public Memory Memory { get; } - - public void Dispose() - { - // Do nothing, the underlying memory is owned by the parent set. - } - } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs index 80b41c5e4e..5e3f6d0c9f 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs @@ -25,12 +25,10 @@ public class DominantCostRangeTests { // arrange DominantCostRange dominantCostRange = new(); - using Vp8LHistogram histogram = new(Configuration.Default.MemoryAllocator, 10) - { - LiteralCost = 1.0d, - RedCost = 2.0d, - BlueCost = 3.0d - }; + using Vp8LHistogram histogram = Vp8LHistogram.Create(Configuration.Default.MemoryAllocator, 10); + histogram.LiteralCost = 1.0d; + histogram.RedCost = 2.0d; + histogram.BlueCost = 3.0d; // act dominantCostRange.UpdateDominantCostRange(histogram); @@ -59,13 +57,12 @@ public class DominantCostRangeTests RedMax = 191.0, RedMin = 109.0 }; - using Vp8LHistogram histogram = new(Configuration.Default.MemoryAllocator, 6) - { - LiteralCost = 247.0d, - RedCost = 112.0d, - BlueCost = 202.0d, - BitCost = 733.0d - }; + using Vp8LHistogram histogram = Vp8LHistogram.Create(Configuration.Default.MemoryAllocator, 6); + histogram.LiteralCost = 247.0d; + histogram.RedCost = 112.0d; + histogram.BlueCost = 202.0d; + histogram.BitCost = 733.0d; + dominantCostRange.UpdateDominantCostRange(histogram); // act diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs index 755b735452..c27d30eeab 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs @@ -78,15 +78,15 @@ public class Vp8LHistogramTests } MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; - using Vp8LHistogram histogram0 = new(memoryAllocator, backwardRefs, 3); - using Vp8LHistogram histogram1 = new(memoryAllocator, backwardRefs, 3); + using Vp8LHistogram histogram0 = Vp8LHistogram.Create(memoryAllocator, backwardRefs, 3); + using Vp8LHistogram histogram1 = Vp8LHistogram.Create(memoryAllocator, backwardRefs, 3); for (int i = 0; i < 5; i++) { histogram0.IsUsed(i, true); histogram1.IsUsed(i, true); } - using Vp8LHistogram output = new(memoryAllocator, 3); + using Vp8LHistogram output = Vp8LHistogram.Create(memoryAllocator, 3); // act histogram0.Add(histogram1, output); From 83ced124c4a077eea9d913de7b6b2c74b62be182 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 16 Oct 2023 15:38:58 +1000 Subject: [PATCH 004/219] Split Vp8LHistogram and clean up --- .../Webp/Lossless/BackwardReferenceEncoder.cs | 4 +- .../Formats/Webp/Lossless/CostModel.cs | 2 +- .../Formats/Webp/Lossless/HistogramEncoder.cs | 10 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 2 +- .../Formats/Webp/Lossless/Vp8LHistogram.cs | 99 ++++++++++--------- .../Formats/Webp/Lossless/Vp8LHistogramSet.cs | 62 ++++++------ .../Formats/WebP/DominantCostRangeTests.cs | 4 +- .../Formats/WebP/Vp8LHistogramTests.cs | 6 +- 8 files changed, 98 insertions(+), 91 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs index 185ba1e346..211185dbba 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs @@ -85,7 +85,7 @@ internal static class BackwardReferenceEncoder } // Keep the best backward references. - using Vp8LHistogram histo = Vp8LHistogram.Create(memoryAllocator, worst, cacheBitsTmp); + using OwnedVp8LHistogram histo = OwnedVp8LHistogram.Create(memoryAllocator, worst, cacheBitsTmp); double bitCost = histo.EstimateBits(stats, bitsEntropy); if (lz77TypeBest == 0 || bitCost < bitCostBest) @@ -102,7 +102,7 @@ internal static class BackwardReferenceEncoder { Vp8LHashChain hashChainTmp = lz77TypeBest == (int)Vp8LLz77Type.Lz77Standard ? hashChain : hashChainBox!; BackwardReferencesTraceBackwards(width, height, memoryAllocator, bgra, cacheBits, hashChainTmp, best, worst); - using Vp8LHistogram histo = Vp8LHistogram.Create(memoryAllocator, worst, cacheBits); + using OwnedVp8LHistogram histo = OwnedVp8LHistogram.Create(memoryAllocator, worst, cacheBits); double bitCostTrace = histo.EstimateBits(stats, bitsEntropy); if (bitCostTrace < bitCostBest) { diff --git a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs index 94d60b4ee3..beebc48abc 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/CostModel.cs @@ -37,7 +37,7 @@ internal class CostModel public void Build(int xSize, int cacheBits, Vp8LBackwardRefs backwardRefs) { - using Vp8LHistogram histogram = Vp8LHistogram.Create(this.memoryAllocator, cacheBits); + using OwnedVp8LHistogram histogram = OwnedVp8LHistogram.Create(this.memoryAllocator, cacheBits); // The following code is similar to HistogramCreate but converts the distance to plane code. for (int i = 0; i < backwardRefs.Refs.Count; i++) diff --git a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs index cce0356176..6c2d18a919 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs @@ -172,8 +172,8 @@ internal static class HistogramEncoder // Skip the histogram if it is completely empty, which can happen for tiles with no information (when they are skipped because of LZ77). if (!origHistogram.IsUsed(0) && !origHistogram.IsUsed(1) && !origHistogram.IsUsed(2) && !origHistogram.IsUsed(3) && !origHistogram.IsUsed(4)) { - origHistograms.DisposeAt(i); - histograms.DisposeAt(i); + origHistograms[i] = null; + histograms[i] = null; histogramSymbols[i] = InvalidHistogramSymbol; } else @@ -254,7 +254,7 @@ internal static class HistogramEncoder // Move the (better) merged histogram to its final slot. (histograms[first], curCombo) = (curCombo, histograms[first]); - histograms.DisposeAt(idx); + histograms[idx] = null; indicesToRemove.Add(idx); clusterMappings[clusters[idx]] = clusters[first]; } @@ -415,7 +415,7 @@ internal static class HistogramEncoder // Merge the histograms and remove bestIdx2 from the list. HistogramAdd(histograms[bestIdx2], histograms[bestIdx1], histograms[bestIdx1]); histograms[bestIdx1].BitCost = histoPriorityList[0].CostCombo; - histograms.DisposeAt(bestIdx2); + histograms[bestIdx2] = null; numUsed--; for (int j = 0; j < histoPriorityList.Count;) @@ -512,7 +512,7 @@ internal static class HistogramEncoder histograms[idx1].BitCost = histoPriorityList[0].CostCombo; // Remove merged histogram. - histograms.DisposeAt(idx2); + histograms[idx2] = null; // Remove pairs intersecting the just combined best pair. for (int i = 0; i < histoPriorityList.Count;) diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index b53180a4ff..878d487a86 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -589,7 +589,7 @@ internal class Vp8LEncoder : IDisposable Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0]; this.bitWriter.Reset(bwInit); - using Vp8LHistogram tmpHisto = Vp8LHistogram.Create(this.memoryAllocator, cacheBits); + using OwnedVp8LHistogram tmpHisto = OwnedVp8LHistogram.Create(this.memoryAllocator, cacheBits); using Vp8LHistogramSet histogramImage = new(this.memoryAllocator, histogramImageXySize, cacheBits); // Build histogram image and symbols from backward references. diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs index 023f1c943b..f473977908 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogram.cs @@ -10,13 +10,9 @@ using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.Formats.Webp.Lossless; -internal sealed unsafe class Vp8LHistogram : IDisposable +internal abstract unsafe class Vp8LHistogram { private const uint NonTrivialSym = 0xffffffff; - private readonly IMemoryOwner? bufferOwner; - private readonly Memory buffer; - private readonly MemoryHandle bufferHandle; - private readonly uint* red; private readonly uint* blue; private readonly uint* alpha; @@ -35,32 +31,21 @@ internal sealed unsafe class Vp8LHistogram : IDisposable /// /// Initializes a new instance of the class. /// - /// - /// This constructor should be used when the histogram is a member of a . - /// - /// The backing buffer. + /// The base pointer to the backing memory. /// The backward references to initialize the histogram with. /// The palette code bits. - public Vp8LHistogram(Memory buffer, Vp8LBackwardRefs refs, int paletteCodeBits) - : this(buffer, paletteCodeBits) => this.StoreRefs(refs); + protected Vp8LHistogram(uint* basePointer, Vp8LBackwardRefs refs, int paletteCodeBits) + : this(basePointer, paletteCodeBits) => this.StoreRefs(refs); /// /// Initializes a new instance of the class. /// - /// - /// This constructor should be used when the histogram is a member of a . - /// - /// The backing buffer. + /// The base pointer to the backing memory. /// The palette code bits. - /// Optional buffer owner to dispose. - public Vp8LHistogram(Memory buffer, int paletteCodeBits, IMemoryOwner? bufferOwner = null) + protected Vp8LHistogram(uint* basePointer, int paletteCodeBits) { - this.bufferOwner = bufferOwner; - this.buffer = buffer; - this.bufferHandle = this.buffer.Pin(); this.PaletteCodeBits = paletteCodeBits; - - this.red = (uint*)this.bufferHandle.Pointer; + this.red = basePointer; this.blue = this.red + RedSize; this.alpha = this.blue + BlueSize; this.distance = this.alpha + AlphaSize; @@ -109,27 +94,6 @@ internal sealed unsafe class Vp8LHistogram : IDisposable private Span TotalSpan => new(this.red, BufferSize); - public bool IsDisposed { get; set; } - - /// - /// Creates an that is not a member of a . - /// - public static Vp8LHistogram Create(MemoryAllocator memoryAllocator, int paletteCodeBits) - { - IMemoryOwner bufferOwner = memoryAllocator.Allocate(BufferSize, AllocationOptions.Clean); - return new Vp8LHistogram(bufferOwner.Memory, paletteCodeBits, bufferOwner); - } - - /// - /// Creates an that is not a member of a . - /// - public static Vp8LHistogram Create(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int paletteCodeBits) - { - Vp8LHistogram histogram = Create(memoryAllocator, paletteCodeBits); - histogram.StoreRefs(refs); - return histogram; - } - [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool IsUsed(int index) => this.IsUsedSpan[index] == 1u; @@ -621,14 +585,57 @@ internal sealed unsafe class Vp8LHistogram : IDisposable } } } +} + +internal sealed unsafe class OwnedVp8LHistogram : Vp8LHistogram, IDisposable +{ + private readonly IMemoryOwner bufferOwner; + private MemoryHandle bufferHandle; + private bool isDisposed; + + private OwnedVp8LHistogram( + IMemoryOwner bufferOwner, + ref MemoryHandle bufferHandle, + uint* basePointer, + int paletteCodeBits) + : base(basePointer, paletteCodeBits) + { + this.bufferOwner = bufferOwner; + this.bufferHandle = bufferHandle; + } + + /// + /// Creates an that is not a member of a . + /// + /// The memory allocator. + /// The palette code bits. + public static OwnedVp8LHistogram Create(MemoryAllocator memoryAllocator, int paletteCodeBits) + { + IMemoryOwner bufferOwner = memoryAllocator.Allocate(BufferSize, AllocationOptions.Clean); + MemoryHandle bufferHandle = bufferOwner.Memory.Pin(); + return new OwnedVp8LHistogram(bufferOwner, ref bufferHandle, (uint*)bufferHandle.Pointer, paletteCodeBits); + } + + /// + /// Creates an that is not a member of a . + /// + /// The memory allocator. + /// The backward references to initialize the histogram with. + /// The palette code bits. + public static OwnedVp8LHistogram Create(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int paletteCodeBits) + { + OwnedVp8LHistogram histogram = Create(memoryAllocator, paletteCodeBits); + histogram.StoreRefs(refs); + return histogram; + } public void Dispose() { - if (!this.IsDisposed) + if (!this.isDisposed) { this.bufferHandle.Dispose(); - this.bufferOwner?.Dispose(); - this.IsDisposed = true; + this.bufferOwner.Dispose(); + this.isDisposed = true; } } } diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs index b7b884dfc8..a46838ee67 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LHistogramSet.cs @@ -13,30 +13,39 @@ namespace SixLabors.ImageSharp.Formats.Webp.Lossless; internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable { private readonly IMemoryOwner buffer; + private MemoryHandle bufferHandle; private readonly List items; private bool isDisposed; public Vp8LHistogramSet(MemoryAllocator memoryAllocator, int capacity, int cacheBits) { this.buffer = memoryAllocator.Allocate(Vp8LHistogram.BufferSize * capacity, AllocationOptions.Clean); + this.bufferHandle = this.buffer.Memory.Pin(); - this.items = new List(capacity); - for (int i = 0; i < capacity; i++) + unsafe { - Memory subBuffer = this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize); - this.items.Add(new Vp8LHistogram(subBuffer, cacheBits)); + uint* basePointer = (uint*)this.bufferHandle.Pointer; + this.items = new List(capacity); + for (int i = 0; i < capacity; i++) + { + this.items.Add(new MemberVp8LHistogram(basePointer + (Vp8LHistogram.BufferSize * i), cacheBits)); + } } } public Vp8LHistogramSet(MemoryAllocator memoryAllocator, Vp8LBackwardRefs refs, int capacity, int cacheBits) { this.buffer = memoryAllocator.Allocate(Vp8LHistogram.BufferSize * capacity, AllocationOptions.Clean); + this.bufferHandle = this.buffer.Memory.Pin(); - this.items = new List(capacity); - for (int i = 0; i < capacity; i++) + unsafe { - Memory subBuffer = this.buffer.Memory.Slice(Vp8LHistogram.BufferSize * i, Vp8LHistogram.BufferSize); - this.items.Add(new Vp8LHistogram(subBuffer, refs, cacheBits)); + uint* basePointer = (uint*)this.bufferHandle.Pointer; + this.items = new List(capacity); + for (int i = 0; i < capacity; i++) + { + this.items.Add(new MemberVp8LHistogram(basePointer + (Vp8LHistogram.BufferSize * i), refs, cacheBits)); + } } } @@ -49,30 +58,13 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable public Vp8LHistogram this[int index] { get => this.items[index]; - - // TODO: Should we check and throw for null? set => this.items[index] = value; } - public void DisposeAt(int index) - { - this.CheckDisposed(); - - Vp8LHistogram item = this.items[index]; - item?.Dispose(); - this.items[index] = null; - } - public void RemoveAt(int index) { this.CheckDisposed(); - - Vp8LHistogram item = this.items[index]; - item?.Dispose(); this.items.RemoveAt(index); -#pragma warning disable IDE0059 // Unnecessary assignment of a value - item = null; -#pragma warning restore IDE0059 // Unnecessary assignment of a value } public void Dispose() @@ -82,13 +74,8 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable return; } - foreach (Vp8LHistogram item in this.items) - { - // First, make sure to unpin individual sub buffers. - item?.Dispose(); - } - this.buffer.Dispose(); + this.bufferHandle.Dispose(); this.items.Clear(); this.isDisposed = true; } @@ -107,4 +94,17 @@ internal sealed class Vp8LHistogramSet : IEnumerable, IDisposable } private static void ThrowDisposed() => throw new ObjectDisposedException(nameof(Vp8LHistogramSet)); + + private sealed unsafe class MemberVp8LHistogram : Vp8LHistogram + { + public MemberVp8LHistogram(uint* basePointer, int paletteCodeBits) + : base(basePointer, paletteCodeBits) + { + } + + public MemberVp8LHistogram(uint* basePointer, Vp8LBackwardRefs refs, int paletteCodeBits) + : base(basePointer, refs, paletteCodeBits) + { + } + } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs index 5e3f6d0c9f..9c48e61823 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/DominantCostRangeTests.cs @@ -25,7 +25,7 @@ public class DominantCostRangeTests { // arrange DominantCostRange dominantCostRange = new(); - using Vp8LHistogram histogram = Vp8LHistogram.Create(Configuration.Default.MemoryAllocator, 10); + using OwnedVp8LHistogram histogram = OwnedVp8LHistogram.Create(Configuration.Default.MemoryAllocator, 10); histogram.LiteralCost = 1.0d; histogram.RedCost = 2.0d; histogram.BlueCost = 3.0d; @@ -57,7 +57,7 @@ public class DominantCostRangeTests RedMax = 191.0, RedMin = 109.0 }; - using Vp8LHistogram histogram = Vp8LHistogram.Create(Configuration.Default.MemoryAllocator, 6); + using OwnedVp8LHistogram histogram = OwnedVp8LHistogram.Create(Configuration.Default.MemoryAllocator, 6); histogram.LiteralCost = 247.0d; histogram.RedCost = 112.0d; histogram.BlueCost = 202.0d; diff --git a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs index c27d30eeab..cfe79e49e6 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/Vp8LHistogramTests.cs @@ -78,15 +78,15 @@ public class Vp8LHistogramTests } MemoryAllocator memoryAllocator = Configuration.Default.MemoryAllocator; - using Vp8LHistogram histogram0 = Vp8LHistogram.Create(memoryAllocator, backwardRefs, 3); - using Vp8LHistogram histogram1 = Vp8LHistogram.Create(memoryAllocator, backwardRefs, 3); + using OwnedVp8LHistogram histogram0 = OwnedVp8LHistogram.Create(memoryAllocator, backwardRefs, 3); + using OwnedVp8LHistogram histogram1 = OwnedVp8LHistogram.Create(memoryAllocator, backwardRefs, 3); for (int i = 0; i < 5; i++) { histogram0.IsUsed(i, true); histogram1.IsUsed(i, true); } - using Vp8LHistogram output = Vp8LHistogram.Create(memoryAllocator, 3); + using OwnedVp8LHistogram output = OwnedVp8LHistogram.Create(memoryAllocator, 3); // act histogram0.Add(histogram1, output); From df2f6987a5f649b913bb5013a7cc1f03a86fa2dd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 17 Oct 2023 10:19:54 +1000 Subject: [PATCH 005/219] Do not attempt to read data for chunks of length 0. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 6 ++++++ tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 10 +++++++++- tests/ImageSharp.Tests/TestImages.cs | 2 ++ .../Input/Png/issues/flag_of_germany-0000016446.png | 3 +++ 4 files changed, 20 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Png/issues/flag_of_germany-0000016446.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 065d861e71..b14cdb122b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -15,6 +15,7 @@ using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.Memory.Internals; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; @@ -1569,6 +1570,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals [MethodImpl(InliningOptions.ShortMethod)] private IMemoryOwner ReadChunkData(int length) { + if (length == 0) + { + return new BasicArrayBuffer(Array.Empty()); + } + // We rent the buffer here to return it afterwards in Decode() IMemoryOwner buffer = this.configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index e216832853..04762c3b21 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -7,7 +7,6 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; -using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; using SixLabors.ImageSharp.Tests.TestUtilities.ReferenceCodecs; @@ -612,4 +611,13 @@ public partial class PngDecoderTests "Disco") .Dispose(); } + + [Fact] + public void Binary_PrematureEof() + { + using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446); + + Assert.True(eofHitCounter.EofHitCount <= 2); + Assert.Equal(new Size(200, 120), eofHitCounter.Image.Size); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index c5565bbd85..c33da432bf 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -169,6 +169,8 @@ public static class TestImages // Invalid color type. public const string ColorTypeOne = "Png/xc1n0g08.png"; public const string ColorTypeNine = "Png/xc9n2c08.png"; + + public const string FlagOfGermany0000016446 = "Png/issues/flag_of_germany-0000016446.png"; } } diff --git a/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png b/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png new file mode 100644 index 0000000000..cb8b5bc941 --- /dev/null +++ b/tests/Images/Input/Png/issues/flag_of_germany-0000016446.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:64633823874512ff9f37bd321184d548816e97b8898622ae7d912b59f3099a35 +size 16446 From 2f61d94e37c9f7a954c0f48c4bb47ba0db80f419 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 17 Oct 2023 10:25:50 +1000 Subject: [PATCH 006/219] Update src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs Co-authored-by: Anton Firszov --- src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs index 6c2d18a919..3a96362cfd 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/HistogramEncoder.cs @@ -383,8 +383,7 @@ internal static class HistogramEncoder idx2 = mappings[idx2]; // Calculate cost reduction on combination. - double currCost = 0; - currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost, stats, bitsEntropy); + double currCost = HistoPriorityListPush(histoPriorityList, maxSize, histograms, idx1, idx2, bestCost, stats, bitsEntropy); // Found a better pair? if (currCost < 0) From c7f3aa40cbee9da1c1f40651645b61b3d243aecd Mon Sep 17 00:00:00 2001 From: Jose Elias dos Santos Date: Thu, 19 Oct 2023 18:41:28 -0300 Subject: [PATCH 007/219] [fix]: Fixed Unknown App0 Marker add profileResolver missing --- .../Formats/Jpeg/Components/Decoder/JFifMarker.cs | 3 ++- .../Jpeg/Components/Decoder/ProfileResolver.cs | 8 ++++++++ .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 11 +++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/issues/issue-2564.jpg | 3 +++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Jpg/issues/issue-2564.jpg diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index 7e25e945a5..060572fc3f 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -73,7 +73,8 @@ internal readonly struct JFifMarker : IEquatable { // Some images incorrectly use JFXX as the App0 marker (Issue 2478) if (ProfileResolver.IsProfile(bytes, ProfileResolver.JFifMarker) - || ProfileResolver.IsProfile(bytes, ProfileResolver.JFxxMarker)) + || ProfileResolver.IsProfile(bytes, ProfileResolver.JFxxMarker) + || ProfileResolver.IsProfile(bytes, ProfileResolver.OSQidMaker)) { byte majorVersion = bytes[5]; byte minorVersion = bytes[6]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index c11679feb1..ed916c205b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -24,6 +24,14 @@ internal static class ProfileResolver (byte)'J', (byte)'F', (byte)'X', (byte)'X', (byte)'\0' }; + /// + /// Gets the \n[ID or 10 91 73 68 32 specific markers. + /// + public static ReadOnlySpan OSQidMaker => new[] + { + (byte)'\n', (byte)'[', (byte)'I', (byte)'D', (byte)' ' + }; + /// /// Gets the ICC specific markers. /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index eaa9f82cbb..f872895227 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -326,6 +326,17 @@ public partial class JpegDecoderTests image.CompareToOriginal(provider); } + // https://github.com/SixLabors/ImageSharp/discussions/2564 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2564, PixelTypes.Rgba32)] + public void Issue2564_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } + [Theory] [WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.L8)] public void DecodeHang(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index c5565bbd85..1d8cfd335b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -291,6 +291,7 @@ public static class TestImages public const string Issue2334_NotEnoughBytesA = "Jpg/issues/issue-2334-a.jpg"; public const string Issue2334_NotEnoughBytesB = "Jpg/issues/issue-2334-b.jpg"; public const string Issue2478_JFXX = "Jpg/issues/issue-2478-jfxx.jpg"; + public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public static class Fuzz diff --git a/tests/Images/Input/Jpg/issues/issue-2564.jpg b/tests/Images/Input/Jpg/issues/issue-2564.jpg new file mode 100644 index 0000000000..2f0b581032 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2564.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:08f215c777b6fe8e315f18b7f93611c90fa86fefb8e3d37181890afb3068d8bd +size 939150 From 6f52a0d13c38bceecb9187534996cf21b83f1483 Mon Sep 17 00:00:00 2001 From: Poker Date: Sat, 21 Oct 2023 10:40:50 +0800 Subject: [PATCH 008/219] Preparation --- src/ImageSharp/Formats/Webp/AlphaEncoder.cs | 42 ++++----- .../Formats/Webp/AnimationFrameData.cs | 43 +++++++++ .../Formats/Webp/BitWriter/BitWriterBase.cs | 93 +++++++++++++------ .../Formats/Webp/BitWriter/Vp8BitWriter.cs | 11 +-- .../Formats/Webp/BitWriter/Vp8LBitWriter.cs | 11 ++- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 80 ++++++++-------- .../Formats/Webp/Lossy/Vp8Encoder.cs | 4 +- .../Formats/Webp/Lossy/YuvConversion.cs | 6 +- .../Formats/Webp/WebpAnimationDecoder.cs | 42 +-------- .../Formats/Webp/WebpAnimationEncoder.cs | 12 +++ .../Formats/Webp/WebpChunkParsingUtils.cs | 52 +++++++---- src/ImageSharp/Formats/Webp/WebpChunkType.cs | 9 ++ src/ImageSharp/Formats/Webp/WebpConstants.cs | 33 ------- .../Formats/Webp/WebpDecoderCore.cs | 5 - .../Formats/WebP/YuvConversionTests.cs | 4 +- 15 files changed, 248 insertions(+), 199 deletions(-) create mode 100644 src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs diff --git a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs index 596715b205..a18d44fde4 100644 --- a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs @@ -19,7 +19,7 @@ internal static class AlphaEncoder /// Data is either compressed as lossless webp image or uncompressed. /// /// The pixel format. - /// The to encode from. + /// The to encode from. /// The global configuration. /// The memory manager. /// Whether to skip metadata encoding. @@ -27,7 +27,7 @@ internal static class AlphaEncoder /// The size in bytes of the alpha data. /// The encoded alpha data. public static IMemoryOwner EncodeAlpha( - Image image, + ImageFrame frame, Configuration configuration, MemoryAllocator memoryAllocator, bool skipMetadata, @@ -35,9 +35,9 @@ internal static class AlphaEncoder out int size) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; - IMemoryOwner alphaData = ExtractAlphaChannel(image, configuration, memoryAllocator); + int width = frame.Width; + int height = frame.Height; + IMemoryOwner alphaData = ExtractAlphaChannel(frame, configuration, memoryAllocator); if (compress) { @@ -58,9 +58,9 @@ internal static class AlphaEncoder // The transparency information will be stored in the green channel of the ARGB quadruplet. // The green channel is allowed extra transformation steps in the specification -- unlike the other channels, // that can improve compression. - using Image alphaAsImage = DispatchAlphaToGreen(image, alphaData.GetSpan()); + using ImageFrame alphaAsFrame = DispatchAlphaToGreen(frame, alphaData.GetSpan()); - size = lossLessEncoder.EncodeAlphaImageData(alphaAsImage, alphaData); + size = lossLessEncoder.EncodeAlphaImageData(alphaAsFrame, alphaData); return alphaData; } @@ -73,45 +73,45 @@ internal static class AlphaEncoder /// Store the transparency in the green channel. /// /// The pixel format. - /// The to encode from. + /// The to encode from. /// A byte sequence of length width * height, containing all the 8-bit transparency values in scan order. - /// The transparency image. - private static Image DispatchAlphaToGreen(Image image, Span alphaData) + /// The transparency frame. + private static ImageFrame DispatchAlphaToGreen(ImageFrame frame, Span alphaData) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; - Image alphaAsImage = new(width, height); + int width = frame.Width; + int height = frame.Height; + ImageFrame alphaAsFrame = new(Configuration.Default, width, height); for (int y = 0; y < height; y++) { - Memory rowBuffer = alphaAsImage.DangerousGetPixelRowMemory(y); + Memory rowBuffer = alphaAsFrame.DangerousGetPixelRowMemory(y); Span pixelRow = rowBuffer.Span; Span alphaRow = alphaData.Slice(y * width, width); for (int x = 0; x < width; x++) { // Leave A/R/B channels zero'd. - pixelRow[x] = new Rgba32(0, alphaRow[x], 0, 0); + pixelRow[x] = new(0, alphaRow[x], 0, 0); } } - return alphaAsImage; + return alphaAsFrame; } /// /// Extract the alpha data of the image. /// /// The pixel format. - /// The to encode from. + /// The to encode from. /// The global configuration. /// The memory manager. /// A byte sequence of length width * height, containing all the 8-bit transparency values in scan order. - private static IMemoryOwner ExtractAlphaChannel(Image image, Configuration configuration, MemoryAllocator memoryAllocator) + private static IMemoryOwner ExtractAlphaChannel(ImageFrame frame, Configuration configuration, MemoryAllocator memoryAllocator) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = image.Frames.RootFrame.PixelBuffer; - int height = image.Height; - int width = image.Width; + Buffer2D imageBuffer = frame.PixelBuffer; + int height = frame.Height; + int width = frame.Width; IMemoryOwner alphaDataBuffer = memoryAllocator.Allocate(width * height); Span alphaData = alphaDataBuffer.GetSpan(); diff --git a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs b/src/ImageSharp/Formats/Webp/AnimationFrameData.cs index 714ec428ec..3400fef17d 100644 --- a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs +++ b/src/ImageSharp/Formats/Webp/AnimationFrameData.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.IO; + namespace SixLabors.ImageSharp.Formats.Webp; internal struct AnimationFrameData @@ -10,6 +12,11 @@ internal struct AnimationFrameData /// public uint DataSize; + /// + /// X(3) + Y(3) + Width(3) + Height(3) + Duration(3) + 1 byte for flags. + /// + public const uint HeaderSize = 16; + /// /// The X coordinate of the upper left corner of the frame is Frame X * 2. /// @@ -45,4 +52,40 @@ internal struct AnimationFrameData /// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. /// public AnimationDisposalMethod DisposalMethod; + + /// + /// Reads the animation frame header. + /// + /// The stream to read from. + /// Animation frame data. + public static AnimationFrameData Parse(BufferedReadStream stream) + { + Span buffer = stackalloc byte[4]; + + AnimationFrameData data = new() + { + DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer), + + // 3 bytes for the X coordinate of the upper left corner of the frame. + X = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + + // 3 bytes for the Y coordinate of the upper left corner of the frame. + Y = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + + // Frame width Minus One. + Width = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, + + // Frame height Minus One. + Height = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, + + // Frame duration. + Duration = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + }; + + byte flags = (byte)stream.ReadByte(); + data.DisposalMethod = (flags & 1) == 1 ? AnimationDisposalMethod.Dispose : AnimationDisposalMethod.DoNotDispose; + data.BlendingMethod = (flags & (1 << 1)) != 0 ? AnimationBlendingMethod.DoNotBlend : AnimationBlendingMethod.AlphaBlending; + + return data; + } } diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index ab78d18604..d7787b3a00 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; +using System.Drawing; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -92,7 +93,7 @@ internal abstract class BitWriterBase { stream.Write(WebpConstants.RiffFourCc); BinaryPrimitives.WriteUInt32LittleEndian(this.scratchBuffer.Span, riffSize); - stream.Write(this.scratchBuffer.Span.Slice(0, 4)); + stream.Write(this.scratchBuffer.Span[..4]); stream.Write(WebpConstants.WebpHeader); } @@ -129,7 +130,7 @@ internal abstract class BitWriterBase DebugGuard.NotNull(metadataBytes, nameof(metadataBytes)); uint size = (uint)metadataBytes.Length; - Span buf = this.scratchBuffer.Span.Slice(0, 4); + Span buf = this.scratchBuffer.Span[..4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)chunkType); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, size); @@ -143,6 +144,61 @@ internal abstract class BitWriterBase } } + /// + /// Writes the color profile() to the stream. + /// + /// The stream to write to. + /// The color profile bytes. + protected void WriteColorProfile(Stream stream, byte[] iccProfileBytes) => this.WriteMetadataProfile(stream, iccProfileBytes, WebpChunkType.Iccp); + + /// + /// Writes the animation parameter() to the stream. + /// + /// The stream to write to. + /// + /// The default background color of the canvas in [Blue, Green, Red, Alpha] byte order. + /// This color MAY be used to fill the unused space on the canvas around the frames, + /// as well as the transparent pixels of the first frame. + /// The background color is also used when the Disposal method is 1. + /// + /// The number of times to loop the animation. If it is 0, this means infinitely. + protected void WriteAnimationParameter(Stream stream, uint background, ushort loopCount) + { + Span buf = this.scratchBuffer.Span[..4]; + BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.AnimationParameter); + stream.Write(buf); + BinaryPrimitives.WriteUInt32LittleEndian(buf, sizeof(uint) + sizeof(ushort)); + stream.Write(buf); + BinaryPrimitives.WriteUInt32LittleEndian(buf, background); + stream.Write(buf); + BinaryPrimitives.WriteUInt16LittleEndian(buf[..2], loopCount); + stream.Write(buf[..2]); + } + + /// + /// Writes the animation frame() to the stream. + /// + /// The stream to write to. + /// Animation frame data. + /// Frame data. + protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, byte[] data) + { + uint size = AnimationFrameData.HeaderSize + (uint)data.Length; + Span buf = this.scratchBuffer.Span[..4]; + BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation); + stream.Write(buf); + BinaryPrimitives.WriteUInt32BigEndian(buf, size); + stream.Write(buf); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.X); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Y); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Width - 1); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Height - 1); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration); + byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod); + stream.WriteByte(flag); + stream.Write(data); + } + /// /// Writes the alpha chunk to the stream. /// @@ -152,7 +208,7 @@ internal abstract class BitWriterBase protected void WriteAlphaChunk(Stream stream, Span dataBytes, bool alphaDataIsCompressed) { uint size = (uint)dataBytes.Length + 1; - Span buf = this.scratchBuffer.Span.Slice(0, 4); + Span buf = this.scratchBuffer.Span[..4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Alpha); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, size); @@ -161,7 +217,7 @@ internal abstract class BitWriterBase byte flags = 0; if (alphaDataIsCompressed) { - flags |= 1; + flags = 1; } stream.WriteByte(flags); @@ -174,30 +230,6 @@ internal abstract class BitWriterBase } } - /// - /// Writes the color profile to the stream. - /// - /// The stream to write to. - /// The color profile bytes. - protected void WriteColorProfile(Stream stream, byte[] iccProfileBytes) - { - uint size = (uint)iccProfileBytes.Length; - - Span buf = this.scratchBuffer.Span.Slice(0, 4); - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Iccp); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, size); - stream.Write(buf); - - stream.Write(iccProfileBytes); - - // Add padding byte if needed. - if ((size & 1) == 1) - { - stream.WriteByte(0); - } - } - /// /// Writes a VP8X header to the stream. /// @@ -246,8 +278,9 @@ internal abstract class BitWriterBase flags |= 32; } - Span buf = this.scratchBuffer.Span.Slice(0, 4); - stream.Write(WebpConstants.Vp8XMagicBytes); + Span buf = this.scratchBuffer.Span[..4]; + BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Vp8X); + stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, WebpConstants.Vp8XChunkSize); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, flags); diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs index 5b4eab64a3..597ecef42a 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs @@ -701,12 +701,11 @@ internal class Vp8BitWriter : BitWriterBase private void WriteVp8Header(Stream stream, uint size) { - Span vp8ChunkHeader = stackalloc byte[WebpConstants.ChunkHeaderSize]; - - WebpConstants.Vp8MagicBytes.AsSpan().CopyTo(vp8ChunkHeader); - BinaryPrimitives.WriteUInt32LittleEndian(vp8ChunkHeader[4..], size); - - stream.Write(vp8ChunkHeader); + Span buf = stackalloc byte[WebpConstants.TagSize]; + BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Vp8); + stream.Write(buf); + BinaryPrimitives.WriteUInt32LittleEndian(buf, size); + stream.Write(buf); } private void WriteFrameHeader(Stream stream, uint size0) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs index 9dc7912392..a042f68968 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs @@ -105,7 +105,7 @@ internal class Vp8LBitWriter : BitWriterBase { 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); + return new(clonedBuffer, this.bits, this.used, this.cur); } /// @@ -186,12 +186,13 @@ internal class Vp8LBitWriter : BitWriterBase } // Write magic bytes indicating its a lossless webp. - stream.Write(WebpConstants.Vp8LMagicBytes); + Span scratchBuffer = stackalloc byte[WebpConstants.TagSize]; + BinaryPrimitives.WriteUInt32BigEndian(scratchBuffer, (uint)WebpChunkType.Vp8L); + stream.Write(scratchBuffer); // Write Vp8 Header. - Span scratchBuffer = stackalloc byte[8]; BinaryPrimitives.WriteUInt32LittleEndian(scratchBuffer, size); - stream.Write(scratchBuffer.Slice(0, 4)); + stream.Write(scratchBuffer); stream.WriteByte(WebpConstants.Vp8LHeaderMagicByte); // Write the encoded bytes of the image to the stream. @@ -226,7 +227,7 @@ internal class Vp8LBitWriter : BitWriterBase Span scratchBuffer = stackalloc byte[8]; BinaryPrimitives.WriteUInt64LittleEndian(scratchBuffer, this.bits); - scratchBuffer.Slice(0, 4).CopyTo(this.Buffer.AsSpan(this.cur)); + scratchBuffer[..4].CopyTo(this.Buffer.AsSpan(this.cur)); this.cur += WriterBytes; this.bits >>= WriterBits; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 469e4c9ab0..9b82cc5983 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -254,7 +254,7 @@ internal class Vp8LEncoder : IDisposable XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; // Convert image pixels to bgra array. - bool hasAlpha = this.ConvertPixelsToBgra(image, width, height); + bool hasAlpha = this.ConvertPixelsToBgra(image.Frames.RootFrame, width, height); // Write the image size. this.WriteImageSize(width, height); @@ -263,7 +263,7 @@ internal class Vp8LEncoder : IDisposable this.WriteAlphaAndVersion(hasAlpha); // Encode the main image stream. - this.EncodeStream(image); + this.EncodeStream(image.Frames.RootFrame); // Write bytes from the bitwriter buffer to the stream. this.bitWriter.WriteEncodedImageToStream(stream, exifProfile, xmpProfile, metadata.IccProfile, (uint)width, (uint)height, hasAlpha); @@ -273,23 +273,23 @@ internal class Vp8LEncoder : IDisposable /// Encodes the alpha image data using the webp lossless compression. /// /// The type of the pixel. - /// The to encode from. + /// The to encode from. /// The destination buffer to write the encoded alpha data to. /// The size of the compressed data in bytes. /// If the size of the data is the same as the pixel count, the compression would not yield in smaller data and is left uncompressed. /// - public int EncodeAlphaImageData(Image image, IMemoryOwner alphaData) + public int EncodeAlphaImageData(ImageFrame frame, IMemoryOwner alphaData) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; + int width = frame.Width; + int height = frame.Height; int pixelCount = width * height; // Convert image pixels to bgra array. - this.ConvertPixelsToBgra(image, width, height); + this.ConvertPixelsToBgra(frame, width, height); // The image-stream will NOT contain any headers describing the image dimension, the dimension is already known. - this.EncodeStream(image); + this.EncodeStream(frame); this.bitWriter.Finish(); int size = this.bitWriter.NumBytes(); if (size >= pixelCount) @@ -333,12 +333,12 @@ internal class Vp8LEncoder : IDisposable /// Encodes the image stream using lossless webp format. /// /// The pixel type. - /// The image to encode. - private void EncodeStream(Image image) + /// The frame to encode. + private void EncodeStream(ImageFrame frame) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; + int width = frame.Width; + int height = frame.Height; Span bgra = this.Bgra.GetSpan(); Span encodedData = this.EncodedData.GetSpan(); @@ -447,14 +447,14 @@ internal class Vp8LEncoder : IDisposable /// Converts the pixels of the image to bgra. /// /// The type of the pixels. - /// The image to convert. + /// The frame to convert. /// The width of the image. /// The height of the image. /// true, if the image is non opaque. - private bool ConvertPixelsToBgra(Image image, int width, int height) + private bool ConvertPixelsToBgra(ImageFrame frame, int width, int height) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = image.Frames.RootFrame.PixelBuffer; + Buffer2D imageBuffer = frame.PixelBuffer; bool nonOpaque = false; Span bgra = this.Bgra.GetSpan(); Span bgraBytes = MemoryMarshal.Cast(bgra); @@ -1149,35 +1149,41 @@ internal class Vp8LEncoder : IDisposable entropyComp[j] = bitEntropy.BitsEntropyRefine(); } - entropy[(int)EntropyIx.Direct] = entropyComp[(int)HistoIx.HistoAlpha] + - entropyComp[(int)HistoIx.HistoRed] + - entropyComp[(int)HistoIx.HistoGreen] + - entropyComp[(int)HistoIx.HistoBlue]; - entropy[(int)EntropyIx.Spatial] = entropyComp[(int)HistoIx.HistoAlphaPred] + - entropyComp[(int)HistoIx.HistoRedPred] + - entropyComp[(int)HistoIx.HistoGreenPred] + - entropyComp[(int)HistoIx.HistoBluePred]; - entropy[(int)EntropyIx.SubGreen] = entropyComp[(int)HistoIx.HistoAlpha] + - entropyComp[(int)HistoIx.HistoRedSubGreen] + - entropyComp[(int)HistoIx.HistoGreen] + - entropyComp[(int)HistoIx.HistoBlueSubGreen]; - entropy[(int)EntropyIx.SpatialSubGreen] = entropyComp[(int)HistoIx.HistoAlphaPred] + - entropyComp[(int)HistoIx.HistoRedPredSubGreen] + - entropyComp[(int)HistoIx.HistoGreenPred] + - entropyComp[(int)HistoIx.HistoBluePredSubGreen]; + entropy[(int)EntropyIx.Direct] = + entropyComp[(int)HistoIx.HistoAlpha] + + entropyComp[(int)HistoIx.HistoRed] + + entropyComp[(int)HistoIx.HistoGreen] + + entropyComp[(int)HistoIx.HistoBlue]; + entropy[(int)EntropyIx.Spatial] = + entropyComp[(int)HistoIx.HistoAlphaPred] + + entropyComp[(int)HistoIx.HistoRedPred] + + entropyComp[(int)HistoIx.HistoGreenPred] + + entropyComp[(int)HistoIx.HistoBluePred]; + entropy[(int)EntropyIx.SubGreen] = + entropyComp[(int)HistoIx.HistoAlpha] + + entropyComp[(int)HistoIx.HistoRedSubGreen] + + entropyComp[(int)HistoIx.HistoGreen] + + entropyComp[(int)HistoIx.HistoBlueSubGreen]; + entropy[(int)EntropyIx.SpatialSubGreen] = + entropyComp[(int)HistoIx.HistoAlphaPred] + + entropyComp[(int)HistoIx.HistoRedPredSubGreen] + + entropyComp[(int)HistoIx.HistoGreenPred] + + entropyComp[(int)HistoIx.HistoBluePredSubGreen]; entropy[(int)EntropyIx.Palette] = entropyComp[(int)HistoIx.HistoPalette]; // When including transforms, there is an overhead in bits from // storing them. This overhead is small but matters for small images. // For spatial, there are 14 transformations. - entropy[(int)EntropyIx.Spatial] += LosslessUtils.SubSampleSize(width, transformBits) * - LosslessUtils.SubSampleSize(height, transformBits) * - LosslessUtils.FastLog2(14); + entropy[(int)EntropyIx.Spatial] += + LosslessUtils.SubSampleSize(width, transformBits) * + LosslessUtils.SubSampleSize(height, transformBits) * + LosslessUtils.FastLog2(14); // For color transforms: 24 as only 3 channels are considered in a ColorTransformElement. - entropy[(int)EntropyIx.SpatialSubGreen] += LosslessUtils.SubSampleSize(width, transformBits) * - LosslessUtils.SubSampleSize(height, transformBits) * - LosslessUtils.FastLog2(24); + entropy[(int)EntropyIx.SpatialSubGreen] += + LosslessUtils.SubSampleSize(width, transformBits) * + LosslessUtils.SubSampleSize(height, transformBits) * + LosslessUtils.FastLog2(24); // For palettes, add the cost of storing the palette. // We empirically estimate the cost of a compressed entry as 8 bits. diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index f17d965e87..ce5d3bac11 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -323,7 +323,7 @@ internal class Vp8Encoder : IDisposable Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - bool hasAlpha = YuvConversion.ConvertRgbToYuv(image, this.configuration, this.memoryAllocator, y, u, v); + bool hasAlpha = YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, this.configuration, this.memoryAllocator, y, u, v); int yStride = width; int uvStride = (yStride + 1) >> 1; @@ -393,7 +393,7 @@ internal class Vp8Encoder : IDisposable { // TODO: This can potentially run in an separate task. encodedAlphaData = AlphaEncoder.EncodeAlpha( - image, + image.Frames.RootFrame, this.configuration, this.memoryAllocator, this.skipMetadata, diff --git a/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs b/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs index 8ef7fe9cba..d669a37b74 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs @@ -262,17 +262,17 @@ internal static class YuvConversion /// Converts the RGB values of the image to YUV. /// /// The pixel type of the image. - /// The image to convert. + /// The frame to convert. /// The global configuration. /// The memory allocator. /// Span to store the luma component of the image. /// Span to store the u component of the image. /// Span to store the v component of the image. /// true, if the image contains alpha data. - public static bool ConvertRgbToYuv(Image image, Configuration configuration, MemoryAllocator memoryAllocator, Span y, Span u, Span v) + public static bool ConvertRgbToYuv(ImageFrame frame, Configuration configuration, MemoryAllocator memoryAllocator, Span y, Span u, Span v) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = image.Frames.RootFrame.PixelBuffer; + Buffer2D imageBuffer = frame.PixelBuffer; int width = imageBuffer.Width; int height = imageBuffer.Height; int uvWidth = (width + 1) >> 1; diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 90c9c70b26..65f654dddc 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -138,7 +138,7 @@ internal class WebpAnimationDecoder : IDisposable private uint ReadFrame(BufferedReadStream stream, ref Image? image, ref ImageFrame? previousFrame, uint width, uint height, Color backgroundColor) where TPixel : unmanaged, IPixel { - AnimationFrameData frameData = this.ReadFrameHeader(stream); + AnimationFrameData frameData = AnimationFrameData.Parse(stream); long streamStartPosition = stream.Position; Span buffer = stackalloc byte[4]; @@ -173,7 +173,7 @@ internal class WebpAnimationDecoder : IDisposable ImageFrame imageFrame; if (previousFrame is null) { - image = new Image(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata); + image = new(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata); SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData.Duration); @@ -258,7 +258,7 @@ internal class WebpAnimationDecoder : IDisposable try { - Buffer2D pixelBufferDecoded = decodedImage.Frames.RootFrame.PixelBuffer; + Buffer2D pixelBufferDecoded = decodedImage.GetRootFramePixelBuffer(); if (webpInfo.IsLossless) { WebpLosslessDecoder losslessDecoder = new(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); @@ -353,42 +353,6 @@ internal class WebpAnimationDecoder : IDisposable pixelRegion.Fill(backgroundPixel); } - /// - /// Reads the animation frame header. - /// - /// The stream to read from. - /// Animation frame data. - private AnimationFrameData ReadFrameHeader(BufferedReadStream stream) - { - Span buffer = stackalloc byte[4]; - - AnimationFrameData data = new() - { - DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer), - - // 3 bytes for the X coordinate of the upper left corner of the frame. - X = WebpChunkParsingUtils.ReadUnsignedInt24Bit(stream, buffer), - - // 3 bytes for the Y coordinate of the upper left corner of the frame. - Y = WebpChunkParsingUtils.ReadUnsignedInt24Bit(stream, buffer), - - // Frame width Minus One. - Width = WebpChunkParsingUtils.ReadUnsignedInt24Bit(stream, buffer) + 1, - - // Frame height Minus One. - Height = WebpChunkParsingUtils.ReadUnsignedInt24Bit(stream, buffer) + 1, - - // Frame duration. - Duration = WebpChunkParsingUtils.ReadUnsignedInt24Bit(stream, buffer) - }; - - byte flags = (byte)stream.ReadByte(); - data.DisposalMethod = (flags & 1) == 1 ? AnimationDisposalMethod.Dispose : AnimationDisposalMethod.DoNotDispose; - data.BlendingMethod = (flags & (1 << 1)) != 0 ? AnimationBlendingMethod.DoNotBlend : AnimationBlendingMethod.AlphaBlending; - - return data; - } - /// public void Dispose() => this.alphaData?.Dispose(); } diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs new file mode 100644 index 0000000000..bfa64b6797 --- /dev/null +++ b/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs @@ -0,0 +1,12 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Webp; + +/// +/// Encoder for animated webp images. +/// +public class WebpAnimationEncoder +{ + // 可能不需要这个屌东西 +} diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index a7ae474e46..becd622e17 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -2,13 +2,12 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; +using System.Drawing; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; -using SixLabors.ImageSharp.Metadata.Profiles.Exif; -using SixLabors.ImageSharp.Metadata.Profiles.Xmp; namespace SixLabors.ImageSharp.Formats.Webp; @@ -91,7 +90,7 @@ internal static class WebpChunkParsingUtils uint tmp = BinaryPrimitives.ReadUInt16LittleEndian(buffer); uint width = tmp & 0x3fff; sbyte xScale = (sbyte)(tmp >> 6); - tmp = BinaryPrimitives.ReadUInt16LittleEndian(buffer.Slice(2)); + tmp = BinaryPrimitives.ReadUInt16LittleEndian(buffer[2..]); uint height = tmp & 0x3fff; sbyte yScale = (sbyte)(tmp >> 6); remaining -= 7; @@ -105,14 +104,14 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowImageFormatException("bad partition length"); } - var vp8FrameHeader = new Vp8FrameHeader() + Vp8FrameHeader vp8FrameHeader = new() { KeyFrame = true, Profile = (sbyte)version, PartitionLength = partitionLength }; - var bitReader = new Vp8BitReader( + Vp8BitReader bitReader = new( stream, remaining, memoryAllocator, @@ -121,7 +120,7 @@ internal static class WebpChunkParsingUtils Remaining = remaining }; - return new WebpImageInfo() + return new() { Width = width, Height = height, @@ -145,7 +144,7 @@ internal static class WebpChunkParsingUtils // VP8 data size. uint imageDataSize = ReadChunkSize(stream, buffer); - var bitReader = new Vp8LBitReader(stream, imageDataSize, memoryAllocator); + Vp8LBitReader bitReader = new(stream, imageDataSize, memoryAllocator); // One byte signature, should be 0x2f. uint signature = bitReader.ReadValue(8); @@ -174,7 +173,7 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowNotSupportedException($"Unexpected version number {version} found in VP8L header"); } - return new WebpImageInfo() + return new() { Width = width, Height = height, @@ -231,13 +230,13 @@ internal static class WebpChunkParsingUtils } // 3 bytes for the width. - uint width = ReadUnsignedInt24Bit(stream, buffer) + 1; + uint width = ReadUInt24LittleEndian(stream, buffer) + 1; // 3 bytes for the height. - uint height = ReadUnsignedInt24Bit(stream, buffer) + 1; + uint height = ReadUInt24LittleEndian(stream, buffer) + 1; // Read all the chunks in the order they occur. - var info = new WebpImageInfo() + WebpImageInfo info = new() { Width = width, Height = height, @@ -253,7 +252,7 @@ internal static class WebpChunkParsingUtils /// The stream to read from. /// The buffer to store the read data into. /// A unsigned 24 bit integer. - public static uint ReadUnsignedInt24Bit(BufferedReadStream stream, Span buffer) + public static uint ReadUInt24LittleEndian(BufferedReadStream stream, Span buffer) { if (stream.Read(buffer, 0, 3) == 3) { @@ -261,7 +260,28 @@ internal static class WebpChunkParsingUtils return BinaryPrimitives.ReadUInt32LittleEndian(buffer); } - throw new ImageFormatException("Invalid Webp data, could not read unsigned integer."); + throw new ImageFormatException("Invalid Webp data, could not read unsigned 24 bit integer."); + } + + /// + /// Writes a unsigned 24 bit integer. + /// + /// The stream to read from. + /// The uint24 data to write. + public static unsafe void WriteUInt24LittleEndian(Stream stream, uint data) + { + if (data >= 1 << 24) + { + throw new InvalidDataException($"Invalid data, {data} is not a unsigned 24 bit integer."); + } + + uint* ptr = &data; + byte* b = (byte*)ptr; + + // Write the data in little endian. + stream.WriteByte(b[0]); + stream.WriteByte(b[1]); + stream.WriteByte(b[2]); } /// @@ -298,7 +318,7 @@ internal static class WebpChunkParsingUtils if (stream.Read(buffer) == 4) { - var chunkType = (WebpChunkType)BinaryPrimitives.ReadUInt32BigEndian(buffer); + WebpChunkType chunkType = (WebpChunkType)BinaryPrimitives.ReadUInt32BigEndian(buffer); return chunkType; } @@ -335,7 +355,7 @@ internal static class WebpChunkParsingUtils if (metadata.ExifProfile != null) { - metadata.ExifProfile = new ExifProfile(exifData); + metadata.ExifProfile = new(exifData); } break; @@ -349,7 +369,7 @@ internal static class WebpChunkParsingUtils if (metadata.XmpProfile != null) { - metadata.XmpProfile = new XmpProfile(xmpData); + metadata.XmpProfile = new(xmpData); } break; diff --git a/src/ImageSharp/Formats/Webp/WebpChunkType.cs b/src/ImageSharp/Formats/Webp/WebpChunkType.cs index 802d7f7288..5836dc6c09 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkType.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkType.cs @@ -12,45 +12,54 @@ internal enum WebpChunkType : uint /// /// Header signaling the use of the VP8 format. /// + /// VP8 (Single) Vp8 = 0x56503820U, /// /// Header signaling the image uses lossless encoding. /// + /// VP8L (Single) Vp8L = 0x5650384CU, /// /// Header for a extended-VP8 chunk. /// + /// VP8X (Single) Vp8X = 0x56503858U, /// /// Chunk contains information about the alpha channel. /// + /// ALPH (Single) Alpha = 0x414C5048U, /// /// Chunk which contains a color profile. /// + /// ICCP (Single) Iccp = 0x49434350U, /// /// Chunk which contains EXIF metadata about the image. /// + /// EXIF (Single) Exif = 0x45584946U, /// /// Chunk contains XMP metadata about the image. /// + /// XMP (Single) Xmp = 0x584D5020U, /// /// For an animated image, this chunk contains the global parameters of the animation. /// + /// ANIM (Single) AnimationParameter = 0x414E494D, /// /// For animated images, this chunk contains information about a single frame. If the Animation flag is not set, then this chunk SHOULD NOT be present. /// + /// ANMF (Multiple) Animation = 0x414E4D46, } diff --git a/src/ImageSharp/Formats/Webp/WebpConstants.cs b/src/ImageSharp/Formats/Webp/WebpConstants.cs index d105d8dd62..1433772757 100644 --- a/src/ImageSharp/Formats/Webp/WebpConstants.cs +++ b/src/ImageSharp/Formats/Webp/WebpConstants.cs @@ -33,39 +33,6 @@ internal static class WebpConstants /// public const byte Vp8LHeaderMagicByte = 0x2F; - /// - /// Signature bytes identifying a lossy image. - /// - public static readonly byte[] Vp8MagicBytes = - { - 0x56, // V - 0x50, // P - 0x38, // 8 - 0x20 // ' ' - }; - - /// - /// Signature bytes identifying a lossless image. - /// - public static readonly byte[] Vp8LMagicBytes = - { - 0x56, // V - 0x50, // P - 0x38, // 8 - 0x4C // L - }; - - /// - /// Signature bytes identifying a VP8X header. - /// - public static readonly byte[] Vp8XMagicBytes = - { - 0x56, // V - 0x50, // P - 0x38, // 8 - 0x58 // X - }; - /// /// The header bytes identifying RIFF file. /// diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 8832ac1068..63d3e1aead 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -93,11 +93,6 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable return animationDecoder.Decode(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize); } - if (this.webImageInfo.Features is { Animation: true }) - { - WebpThrowHelper.ThrowNotSupportedException("Animations are not supported"); - } - image = new Image(this.configuration, (int)this.webImageInfo.Width, (int)this.webImageInfo.Height, metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.webImageInfo.IsLossless) diff --git a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs index 9b03a447a9..433b280bc3 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs @@ -143,7 +143,7 @@ public class YuvConversionTests }; // act - YuvConversion.ConvertRgbToYuv(image, config, memoryAllocator, y, u, v); + YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, config, memoryAllocator, y, u, v); // assert Assert.True(expectedY.AsSpan().SequenceEqual(y)); @@ -249,7 +249,7 @@ public class YuvConversionTests }; // act - YuvConversion.ConvertRgbToYuv(image, config, memoryAllocator, y, u, v); + YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, config, memoryAllocator, y, u, v); // assert Assert.True(expectedY.AsSpan().SequenceEqual(y)); From 62ab3a1eef3c9e9af4af683f512471f81bf3e5d4 Mon Sep 17 00:00:00 2001 From: Poker Date: Sun, 22 Oct 2023 22:54:33 +0800 Subject: [PATCH 009/219] refactor --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 11 +- .../Formats/Webp/BitWriter/Vp8BitWriter.cs | 104 +++++++++--------- .../Formats/Webp/Lossy/Vp8EncIterator.cs | 5 + .../Formats/Webp/Lossy/Vp8Encoder.cs | 4 +- .../Formats/Webp/WebpAnimationDecoder.cs | 5 + 5 files changed, 73 insertions(+), 56 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index d7787b3a00..4252f895b8 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; -using System.Drawing; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -181,7 +180,7 @@ internal abstract class BitWriterBase /// The stream to write to. /// Animation frame data. /// Frame data. - protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, byte[] data) + protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, Span data) { uint size = AnimationFrameData.HeaderSize + (uint)data.Length; Span buf = this.scratchBuffer.Span[..4]; @@ -260,6 +259,14 @@ internal abstract class BitWriterBase flags |= 8; } + /* + if (isAnimated) + { + // Set animated flag. + flags |= 2; + } + */ + if (xmpProfile != null) { // Set xmp bit. diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs index 597ecef42a..cd84f109eb 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs @@ -116,7 +116,7 @@ internal class Vp8BitWriter : BitWriterBase else { this.PutBit(v >= 9, 165); - this.PutBit(!((v & 1) != 0), 145); + this.PutBit((v & 1) == 0, 145); } } else @@ -462,7 +462,7 @@ internal class Vp8BitWriter : BitWriterBase Vp8BitWriter bitWriterPartZero = new(expectedSize, this.enc); // Partition #0 with header and partition sizes. - uint size0 = this.GeneratePartition0(bitWriterPartZero); + uint size0 = bitWriterPartZero.GeneratePartition0(); uint vp8Size = WebpConstants.Vp8FrameHeaderSize + size0; vp8Size += numBytes; @@ -495,47 +495,47 @@ internal class Vp8BitWriter : BitWriterBase } } - private uint GeneratePartition0(Vp8BitWriter bitWriter) + private uint GeneratePartition0() { - bitWriter.PutBitUniform(0); // colorspace - bitWriter.PutBitUniform(0); // clamp type + this.PutBitUniform(0); // colorspace + this.PutBitUniform(0); // clamp type - this.WriteSegmentHeader(bitWriter); - this.WriteFilterHeader(bitWriter); + this.WriteSegmentHeader(); + this.WriteFilterHeader(); - bitWriter.PutBits(0, 2); + this.PutBits(0, 2); - this.WriteQuant(bitWriter); - bitWriter.PutBitUniform(0); - this.WriteProbas(bitWriter); - this.CodeIntraModes(bitWriter); + this.WriteQuant(); + this.PutBitUniform(0); + this.WriteProbas(); + this.CodeIntraModes(); - bitWriter.Finish(); + this.Finish(); - return (uint)bitWriter.NumBytes(); + return (uint)this.NumBytes(); } - private void WriteSegmentHeader(Vp8BitWriter bitWriter) + private void WriteSegmentHeader() { Vp8EncSegmentHeader hdr = this.enc.SegmentHeader; Vp8EncProba proba = this.enc.Proba; - if (bitWriter.PutBitUniform(hdr.NumSegments > 1 ? 1 : 0) != 0) + if (this.PutBitUniform(hdr.NumSegments > 1 ? 1 : 0) != 0) { // We always 'update' the quant and filter strength values. int updateData = 1; - bitWriter.PutBitUniform(hdr.UpdateMap ? 1 : 0); - if (bitWriter.PutBitUniform(updateData) != 0) + this.PutBitUniform(hdr.UpdateMap ? 1 : 0); + if (this.PutBitUniform(updateData) != 0) { // We always use absolute values, not relative ones. - bitWriter.PutBitUniform(1); // (segment_feature_mode = 1. Paragraph 9.3.) + this.PutBitUniform(1); // (segment_feature_mode = 1. Paragraph 9.3.) for (int s = 0; s < WebpConstants.NumMbSegments; ++s) { - bitWriter.PutSignedBits(this.enc.SegmentInfos[s].Quant, 7); + this.PutSignedBits(this.enc.SegmentInfos[s].Quant, 7); } for (int s = 0; s < WebpConstants.NumMbSegments; ++s) { - bitWriter.PutSignedBits(this.enc.SegmentInfos[s].FStrength, 6); + this.PutSignedBits(this.enc.SegmentInfos[s].FStrength, 6); } } @@ -543,50 +543,50 @@ internal class Vp8BitWriter : BitWriterBase { for (int s = 0; s < 3; ++s) { - if (bitWriter.PutBitUniform(proba.Segments[s] != 255 ? 1 : 0) != 0) + if (this.PutBitUniform(proba.Segments[s] != 255 ? 1 : 0) != 0) { - bitWriter.PutBits(proba.Segments[s], 8); + this.PutBits(proba.Segments[s], 8); } } } } } - private void WriteFilterHeader(Vp8BitWriter bitWriter) + private void WriteFilterHeader() { Vp8FilterHeader hdr = this.enc.FilterHeader; bool useLfDelta = hdr.I4x4LfDelta != 0; - bitWriter.PutBitUniform(hdr.Simple ? 1 : 0); - bitWriter.PutBits((uint)hdr.FilterLevel, 6); - bitWriter.PutBits((uint)hdr.Sharpness, 3); - if (bitWriter.PutBitUniform(useLfDelta ? 1 : 0) != 0) + this.PutBitUniform(hdr.Simple ? 1 : 0); + this.PutBits((uint)hdr.FilterLevel, 6); + this.PutBits((uint)hdr.Sharpness, 3); + if (this.PutBitUniform(useLfDelta ? 1 : 0) != 0) { // '0' is the default value for i4x4LfDelta at frame #0. bool needUpdate = hdr.I4x4LfDelta != 0; - if (bitWriter.PutBitUniform(needUpdate ? 1 : 0) != 0) + if (this.PutBitUniform(needUpdate ? 1 : 0) != 0) { // we don't use refLfDelta => emit four 0 bits. - bitWriter.PutBits(0, 4); + this.PutBits(0, 4); // we use modeLfDelta for i4x4 - bitWriter.PutSignedBits(hdr.I4x4LfDelta, 6); - bitWriter.PutBits(0, 3); // all others unused. + this.PutSignedBits(hdr.I4x4LfDelta, 6); + this.PutBits(0, 3); // all others unused. } } } // Nominal quantization parameters - private void WriteQuant(Vp8BitWriter bitWriter) + private void WriteQuant() { - bitWriter.PutBits((uint)this.enc.BaseQuant, 7); - bitWriter.PutSignedBits(this.enc.DqY1Dc, 4); - bitWriter.PutSignedBits(this.enc.DqY2Dc, 4); - bitWriter.PutSignedBits(this.enc.DqY2Ac, 4); - bitWriter.PutSignedBits(this.enc.DqUvDc, 4); - bitWriter.PutSignedBits(this.enc.DqUvAc, 4); + this.PutBits((uint)this.enc.BaseQuant, 7); + this.PutSignedBits(this.enc.DqY1Dc, 4); + this.PutSignedBits(this.enc.DqY2Dc, 4); + this.PutSignedBits(this.enc.DqY2Ac, 4); + this.PutSignedBits(this.enc.DqUvDc, 4); + this.PutSignedBits(this.enc.DqUvAc, 4); } - private void WriteProbas(Vp8BitWriter bitWriter) + private void WriteProbas() { Vp8EncProba probas = this.enc.Proba; for (int t = 0; t < WebpConstants.NumTypes; ++t) @@ -599,25 +599,25 @@ internal class Vp8BitWriter : BitWriterBase { byte p0 = probas.Coeffs[t][b].Probabilities[c].Probabilities[p]; bool update = p0 != WebpLookupTables.DefaultCoeffsProba[t, b, c, p]; - if (bitWriter.PutBit(update, WebpLookupTables.CoeffsUpdateProba[t, b, c, p])) + if (this.PutBit(update, WebpLookupTables.CoeffsUpdateProba[t, b, c, p])) { - bitWriter.PutBits(p0, 8); + this.PutBits(p0, 8); } } } } } - if (bitWriter.PutBitUniform(probas.UseSkipProba ? 1 : 0) != 0) + if (this.PutBitUniform(probas.UseSkipProba ? 1 : 0) != 0) { - bitWriter.PutBits(probas.SkipProba, 8); + this.PutBits(probas.SkipProba, 8); } } // Writes the partition #0 modes (that is: all intra modes) - private void CodeIntraModes(Vp8BitWriter bitWriter) + private void CodeIntraModes() { - var it = new Vp8EncIterator(this.enc.YTop, this.enc.UvTop, this.enc.Nz, this.enc.MbInfo, this.enc.Preds, this.enc.TopDerr, this.enc.Mbw, this.enc.Mbh); + Vp8EncIterator it = new(this.enc); int predsWidth = this.enc.PredsWidth; do @@ -627,18 +627,18 @@ internal class Vp8BitWriter : BitWriterBase Span preds = it.Preds.AsSpan(predIdx); if (this.enc.SegmentHeader.UpdateMap) { - bitWriter.PutSegment(mb.Segment, this.enc.Proba.Segments); + this.PutSegment(mb.Segment, this.enc.Proba.Segments); } if (this.enc.Proba.UseSkipProba) { - bitWriter.PutBit(mb.Skip, this.enc.Proba.SkipProba); + this.PutBit(mb.Skip, this.enc.Proba.SkipProba); } - if (bitWriter.PutBit(mb.MacroBlockType != 0, 145)) + if (this.PutBit(mb.MacroBlockType != 0, 145)) { // i16x16 - bitWriter.PutI16Mode(preds[0]); + this.PutI16Mode(preds[0]); } else { @@ -649,7 +649,7 @@ internal class Vp8BitWriter : BitWriterBase for (int x = 0; x < 4; x++) { byte[] probas = WebpLookupTables.ModesProba[topPred[x], left]; - left = bitWriter.PutI4Mode(it.Preds[predIdx + x], probas); + left = this.PutI4Mode(it.Preds[predIdx + x], probas); } topPred = it.Preds.AsSpan(predIdx); @@ -657,7 +657,7 @@ internal class Vp8BitWriter : BitWriterBase } } - bitWriter.PutUvMode(mb.UvMode); + this.PutUvMode(mb.UvMode); } while (it.Next()); } diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs index 7211f93766..a7c96edb7c 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs @@ -50,6 +50,11 @@ internal class Vp8EncIterator private int uvTopIdx; + public Vp8EncIterator(Vp8Encoder enc) + : this(enc.YTop, enc.UvTop, enc.Nz, enc.MbInfo, enc.Preds, enc.TopDerr, enc.Mbw, enc.Mbh) + { + } + public Vp8EncIterator(byte[] yTop, byte[] uvTop, uint[] nz, Vp8MacroBlockInfo[] mb, byte[] preds, sbyte[] topDerr, int mbw, int mbh) { this.YTop = yTop; diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index ce5d3bac11..c65099af88 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -328,7 +328,7 @@ internal class Vp8Encoder : IDisposable int yStride = width; int uvStride = (yStride + 1) >> 1; - Vp8EncIterator it = new(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh); + Vp8EncIterator it = new(this); Span alphas = stackalloc 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; @@ -520,7 +520,7 @@ internal class Vp8Encoder : IDisposable Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - Vp8EncIterator it = new(this.YTop, this.UvTop, this.Nz, this.MbInfo, this.Preds, this.TopDerr, this.Mbw, this.Mbh); + Vp8EncIterator it = new(this); long size = 0; long sizeP0 = 0; long distortion = 0; diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 65f654dddc..81a7aebdf9 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -162,6 +162,11 @@ internal class WebpAnimationDecoder : IDisposable features.AlphaChunkHeader = alphaChunkHeader; break; case WebpChunkType.Vp8L: + if (hasAlpha) + { + WebpThrowHelper.ThrowNotSupportedException("Alpha channel is not supported for lossless webp images."); + } + webpInfo = WebpChunkParsingUtils.ReadVp8LHeader(this.memoryAllocator, stream, buffer, features); break; default: From 95d36af396d5f57a9d79ca1e3a158c9b18e95a4a Mon Sep 17 00:00:00 2001 From: Poker Date: Mon, 23 Oct 2023 19:50:28 +0800 Subject: [PATCH 010/219] (Vp8) Write total size after writing. Separate the writes of each block --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 47 ++++-- .../Formats/Webp/BitWriter/Vp8BitWriter.cs | 135 +++++++----------- .../Formats/Webp/BitWriter/Vp8LBitWriter.cs | 10 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 8 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 27 ++-- .../Formats/Webp/WebpChunkParsingUtils.cs | 11 +- .../Metadata/Profiles/ICC/IccProfile.cs | 4 +- 7 files changed, 116 insertions(+), 126 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 4252f895b8..b82b764fc3 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -4,6 +4,7 @@ using System.Buffers.Binary; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; namespace SixLabors.ImageSharp.Formats.Webp.BitWriter; @@ -41,17 +42,23 @@ internal abstract class BitWriterBase public byte[] Buffer => this.buffer; + /// + /// Gets the number of bytes of the encoded image data. + /// + /// The number of bytes of the image data. + public abstract int NumBytes { get; } + /// /// Writes the encoded bytes of the image to the stream. Call Finish() before this. /// /// The stream to write to. - public void WriteToStream(Stream stream) => stream.Write(this.Buffer.AsSpan(0, this.NumBytes())); + public void WriteToStream(Stream stream) => stream.Write(this.Buffer.AsSpan(0, this.NumBytes)); /// /// Writes the encoded bytes of the image to the given buffer. Call Finish() before this. /// /// The destination buffer. - public void WriteToBuffer(Span dest) => this.Buffer.AsSpan(0, this.NumBytes()).CopyTo(dest); + public void WriteToBuffer(Span dest) => this.Buffer.AsSpan(0, this.NumBytes).CopyTo(dest); /// /// Resizes the buffer to write to. @@ -59,12 +66,6 @@ internal abstract class BitWriterBase /// The extra size in bytes needed. public abstract void BitWriterResize(int extraSize); - /// - /// Returns the number of bytes of the encoded image data. - /// - /// The number of bytes of the image data. - public abstract int NumBytes(); - /// /// Flush leftover bits. /// @@ -86,6 +87,7 @@ internal abstract class BitWriterBase /// /// Writes the RIFF header to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The block length. protected void WriteRiffHeader(Stream stream, uint riffSize) @@ -99,6 +101,7 @@ internal abstract class BitWriterBase /// /// Calculates the chunk size of EXIF, XMP or ICCP metadata. /// + /// Think of it as a static method — none of the other members are called except for /// The metadata profile bytes. /// The metadata chunk size in bytes. protected static uint MetadataChunkSize(byte[] metadataBytes) @@ -118,9 +121,26 @@ internal abstract class BitWriterBase return WebpConstants.ChunkHeaderSize + alphaSize + (alphaSize & 1); } + /// + /// Overwrites ides the write file size. + /// + /// The stream to write to. + protected static void OverwriteFileSize(Stream stream) + { + uint position = (uint)stream.Position; + stream.Position = 4; + byte[] buffer = new byte[4]; + + // "RIFF"(4)+uint32 size(4) + BinaryPrimitives.WriteUInt32LittleEndian(buffer, position - WebpConstants.ChunkHeaderSize); + stream.Write(buffer); + stream.Position = position; + } + /// /// Writes a metadata profile (EXIF or XMP) to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The metadata profile's bytes. /// The chuck type to write. @@ -146,6 +166,7 @@ internal abstract class BitWriterBase /// /// Writes the color profile() to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The color profile bytes. protected void WriteColorProfile(Stream stream, byte[] iccProfileBytes) => this.WriteMetadataProfile(stream, iccProfileBytes, WebpChunkType.Iccp); @@ -153,6 +174,7 @@ internal abstract class BitWriterBase /// /// Writes the animation parameter() to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// /// The default background color of the canvas in [Blue, Green, Red, Alpha] byte order. @@ -177,6 +199,7 @@ internal abstract class BitWriterBase /// /// Writes the animation frame() to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// Animation frame data. /// Frame data. @@ -201,6 +224,7 @@ internal abstract class BitWriterBase /// /// Writes the alpha chunk to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The alpha channel data bytes. /// Indicates, if the alpha channel data is compressed. @@ -232,14 +256,15 @@ internal abstract class BitWriterBase /// /// Writes a VP8X header to the stream. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// A exif profile or null, if it does not exist. /// A XMP profile or null, if it does not exist. - /// The color profile bytes. + /// The color profile. /// The width of the image. /// The height of the image. /// Flag indicating, if a alpha channel is present. - protected void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, byte[]? iccProfileBytes, uint width, uint height, bool hasAlpha) + protected void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha) { if (width > MaxDimension || height > MaxDimension) { @@ -279,7 +304,7 @@ internal abstract class BitWriterBase flags |= 16; } - if (iccProfileBytes != null) + if (iccProfile != null) { // Set iccp flag. flags |= 32; diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs index cd84f109eb..5dd5d335de 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs @@ -72,7 +72,7 @@ internal class Vp8BitWriter : BitWriterBase } /// - public override int NumBytes() => (int)this.pos; + public override int NumBytes => (int)this.pos; public int PutCoeffs(int ctx, Vp8Residual residual) { @@ -395,67 +395,58 @@ internal class Vp8BitWriter : BitWriterBase } /// - /// Writes the encoded image to the stream. + /// Write the trunks before data trunk. /// + /// Think of it as a static method — none of the other members are called except for /// The stream to write to. + /// The width of the image. + /// The height of the image. /// The exif profile. /// The XMP profile. /// The color profile. - /// The width of the image. - /// The height of the image. /// Flag indicating, if a alpha channel is present. /// The alpha channel data. /// Indicates, if the alpha data is compressed. - public void WriteEncodedImageToStream( + public void WriteTrunksBeforeData( Stream stream, + uint width, + uint height, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, - uint width, - uint height, bool hasAlpha, Span alphaData, bool alphaDataIsCompressed) { - bool isVp8X = false; - byte[]? exifBytes = null; - byte[]? xmpBytes = null; - byte[]? iccProfileBytes = null; - uint riffSize = 0; - if (exifProfile != null) - { - isVp8X = true; - exifBytes = exifProfile.ToByteArray(); - riffSize += MetadataChunkSize(exifBytes!); - } + // Write file size later + this.WriteRiffHeader(stream, 0); - if (xmpProfile != null) + // Write VP8X, header if necessary. + bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha; + if (isVp8X) { - isVp8X = true; - xmpBytes = xmpProfile.Data; - riffSize += MetadataChunkSize(xmpBytes!); - } + this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); - if (iccProfile != null) - { - isVp8X = true; - iccProfileBytes = iccProfile.ToByteArray(); - riffSize += MetadataChunkSize(iccProfileBytes); - } + if (iccProfile != null) + { + this.WriteColorProfile(stream, iccProfile.ToByteArray()); + } - if (hasAlpha) - { - isVp8X = true; - riffSize += AlphaChunkSize(alphaData); + if (hasAlpha) + { + this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed); + } } + } - if (isVp8X) - { - riffSize += ExtendedFileChunkSize; - } + /// + /// Writes the encoded image to the stream. + /// + /// The stream to write to. + public void WriteEncodedImageToStream(Stream stream) + { + uint numBytes = (uint)this.NumBytes; - this.Finish(); - uint numBytes = (uint)this.NumBytes(); int mbSize = this.enc.Mbw * this.enc.Mbh; int expectedSize = (int)((uint)mbSize * 7 / 8); @@ -469,12 +460,10 @@ internal class Vp8BitWriter : BitWriterBase uint pad = vp8Size & 1; vp8Size += pad; - // Compute RIFF size. - // At the minimum it is: "WEBPVP8 nnnn" + VP8 data size. - riffSize += WebpConstants.TagSize + WebpConstants.ChunkHeaderSize + vp8Size; + // Emit header and partition #0 + this.WriteVp8Header(stream, vp8Size); + this.WriteFrameHeader(stream, size0); - // Emit headers and partition #0 - this.WriteWebpHeaders(stream, size0, vp8Size, riffSize, isVp8X, width, height, exifProfile, xmpProfile, iccProfileBytes, hasAlpha, alphaData, alphaDataIsCompressed); bitWriterPartZero.WriteToStream(stream); // Write the encoded image to the stream. @@ -483,16 +472,31 @@ internal class Vp8BitWriter : BitWriterBase { stream.WriteByte(0); } + } + /// + /// Write the trunks after data trunk. + /// + /// Think of it as a static method — none of the other members are called except for + /// The stream to write to. + /// The exif profile. + /// The XMP profile. + public void WriteTrunksAfterData( + Stream stream, + ExifProfile? exifProfile, + XmpProfile? xmpProfile) + { if (exifProfile != null) { - this.WriteMetadataProfile(stream, exifBytes, WebpChunkType.Exif); + this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); } if (xmpProfile != null) { - this.WriteMetadataProfile(stream, xmpBytes, WebpChunkType.Xmp); + this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); } + + OverwriteFileSize(stream); } private uint GeneratePartition0() @@ -512,7 +516,7 @@ internal class Vp8BitWriter : BitWriterBase this.Finish(); - return (uint)this.NumBytes(); + return (uint)this.NumBytes; } private void WriteSegmentHeader() @@ -662,43 +666,6 @@ internal class Vp8BitWriter : BitWriterBase while (it.Next()); } - private void WriteWebpHeaders( - Stream stream, - uint size0, - uint vp8Size, - uint riffSize, - bool isVp8X, - uint width, - uint height, - ExifProfile? exifProfile, - XmpProfile? xmpProfile, - byte[]? iccProfileBytes, - bool hasAlpha, - Span alphaData, - bool alphaDataIsCompressed) - { - this.WriteRiffHeader(stream, riffSize); - - // Write VP8X, header if necessary. - if (isVp8X) - { - this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfileBytes, width, height, hasAlpha); - - if (iccProfileBytes != null) - { - this.WriteColorProfile(stream, iccProfileBytes); - } - - if (hasAlpha) - { - this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed); - } - } - - this.WriteVp8Header(stream, vp8Size); - this.WriteFrameHeader(stream, size0); - } - private void WriteVp8Header(Stream stream, uint size) { Span buf = stackalloc byte[WebpConstants.TagSize]; diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs index a042f68968..0ac1b4038a 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs @@ -47,6 +47,9 @@ internal class Vp8LBitWriter : BitWriterBase { } + /// + public override int NumBytes => this.cur + ((this.used + 7) >> 3); + /// /// Initializes a new instance of the class. /// Used internally for cloning. @@ -98,9 +101,6 @@ internal class Vp8LBitWriter : BitWriterBase this.PutBits((uint)((bits << depth) | symbol), depth + nBits); } - /// - public override int NumBytes() => this.cur + ((this.used + 7) >> 3); - public Vp8LBitWriter Clone() { byte[] clonedBuffer = new byte[this.Buffer.Length]; @@ -166,7 +166,7 @@ internal class Vp8LBitWriter : BitWriterBase } this.Finish(); - uint size = (uint)this.NumBytes(); + uint size = (uint)this.NumBytes; size++; // One byte extra for the VP8L signature. // Write RIFF header. @@ -177,7 +177,7 @@ internal class Vp8LBitWriter : BitWriterBase // Write VP8X, header if necessary. if (isVp8X) { - this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccBytes, width, height, hasAlpha); + this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); if (iccBytes != null) { diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 9b82cc5983..d27bfcd956 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -291,7 +291,7 @@ internal class Vp8LEncoder : IDisposable // The image-stream will NOT contain any headers describing the image dimension, the dimension is already known. this.EncodeStream(frame); this.bitWriter.Finish(); - int size = this.bitWriter.NumBytes(); + int size = this.bitWriter.NumBytes; if (size >= pixelCount) { // Compressing would not yield in smaller data -> leave the data uncompressed. @@ -425,9 +425,9 @@ internal class Vp8LEncoder : IDisposable lowEffort); // If we are better than what we already have. - if (isFirstConfig || this.bitWriter.NumBytes() < bestSize) + if (isFirstConfig || this.bitWriter.NumBytes < bestSize) { - bestSize = this.bitWriter.NumBytes(); + bestSize = this.bitWriter.NumBytes; BitWriterSwap(ref this.bitWriter, ref bitWriterBest); } @@ -676,7 +676,7 @@ internal class Vp8LEncoder : IDisposable this.StoreImageToBitMask(width, this.HistoBits, refsBest, histogramSymbols, huffmanCodes); // Keep track of the smallest image so far. - if (isFirstIteration || (bitWriterBest != null && this.bitWriter.NumBytes() < bitWriterBest.NumBytes())) + if (isFirstIteration || (bitWriterBest != null && this.bitWriter.NumBytes < bitWriterBest.NumBytes)) { Vp8LBitWriter tmp = this.bitWriter; this.bitWriter = bitWriterBest; diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index c65099af88..56397e66d4 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; using SixLabors.ImageSharp.PixelFormats; @@ -408,16 +409,21 @@ internal class Vp8Encoder : IDisposable } } - this.bitWriter.WriteEncodedImageToStream( + this.bitWriter.Finish(); + this.bitWriter.WriteTrunksBeforeData( stream, + (uint)width, + (uint)height, exifProfile, xmpProfile, metadata.IccProfile, - (uint)width, - (uint)height, hasAlpha, alphaData[..alphaDataSize], this.alphaCompression && alphaCompressionSucceeded); + + this.bitWriter.WriteEncodedImageToStream(stream); + + this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile); } finally { @@ -862,10 +868,11 @@ internal class Vp8Encoder : IDisposable this.ResetSegments(); } - this.SegmentHeader.Size = (p[0] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(0, probas[1]))) + - (p[1] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(1, probas[1]))) + - (p[2] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(0, probas[2]))) + - (p[3] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(1, probas[2]))); + this.SegmentHeader.Size = + (p[0] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(0, probas[1]))) + + (p[1] * (LossyUtils.Vp8BitCost(0, probas[0]) + LossyUtils.Vp8BitCost(1, probas[1]))) + + (p[2] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(0, probas[2]))) + + (p[3] * (LossyUtils.Vp8BitCost(1, probas[0]) + LossyUtils.Vp8BitCost(1, probas[2]))); } else { @@ -1027,7 +1034,7 @@ internal class Vp8Encoder : IDisposable it.NzToBytes(); - int pos1 = this.bitWriter.NumBytes(); + int pos1 = this.bitWriter.NumBytes; if (i16) { residual.Init(0, 1, this.Proba); @@ -1054,7 +1061,7 @@ internal class Vp8Encoder : IDisposable } } - int pos2 = this.bitWriter.NumBytes(); + int pos2 = this.bitWriter.NumBytes; // U/V residual.Init(0, 2, this.Proba); @@ -1072,7 +1079,7 @@ internal class Vp8Encoder : IDisposable } } - int pos3 = this.bitWriter.NumBytes(); + int pos3 = this.bitWriter.NumBytes; it.LumaBits = pos2 - pos1; it.UvBits = pos3 - pos2; it.BitCount[segment, i16 ? 1 : 0] += it.LumaBits; diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index becd622e17..9e9f0f7f62 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -76,7 +76,7 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the VP8 magic bytes"); } - if (!buffer.Slice(0, 3).SequenceEqual(WebpConstants.Vp8HeaderMagicBytes)) + if (!buffer[..3].SequenceEqual(WebpConstants.Vp8HeaderMagicBytes)) { WebpThrowHelper.ThrowImageFormatException("VP8 magic bytes not found"); } @@ -111,14 +111,7 @@ internal static class WebpChunkParsingUtils PartitionLength = partitionLength }; - Vp8BitReader bitReader = new( - stream, - remaining, - memoryAllocator, - partitionLength) - { - Remaining = remaining - }; + Vp8BitReader bitReader = new(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; return new() { diff --git a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs index 3b5e438299..be7350bc44 100644 --- a/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/ICC/IccProfile.cs @@ -158,8 +158,7 @@ public sealed class IccProfile : IDeepCloneable Enum.IsDefined(typeof(IccColorSpaceType), this.Header.DataColorSpace) && Enum.IsDefined(typeof(IccColorSpaceType), this.Header.ProfileConnectionSpace) && Enum.IsDefined(typeof(IccRenderingIntent), this.Header.RenderingIntent) && - this.Header.Size >= minSize && - this.Header.Size < maxSize; + this.Header.Size is >= minSize and < maxSize; } /// @@ -175,7 +174,6 @@ public sealed class IccProfile : IDeepCloneable return copy; } - IccWriter writer = new(); return IccWriter.Write(this); } From 437144dab5bb08743aa43e2411ec7bd38963b1c0 Mon Sep 17 00:00:00 2001 From: Poker Date: Mon, 23 Oct 2023 21:14:31 +0800 Subject: [PATCH 011/219] (Vp8L) Write total size after writing. Separate the writes of each block --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 76 ++++++++++++++++++ .../Formats/Webp/BitWriter/Vp8BitWriter.cs | 80 +------------------ .../Formats/Webp/BitWriter/Vp8LBitWriter.cs | 76 +----------------- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 17 +++- .../Formats/Webp/Lossy/Vp8Encoder.cs | 1 - 5 files changed, 97 insertions(+), 153 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index b82b764fc3..ad7d69f130 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -137,6 +137,82 @@ internal abstract class BitWriterBase stream.Position = position; } + /// + /// Write the trunks before data trunk. + /// + /// Think of it as a static method — none of the other members are called except for + /// The stream to write to. + /// The width of the image. + /// The height of the image. + /// The exif profile. + /// The XMP profile. + /// The color profile. + /// Flag indicating, if a alpha channel is present. + /// The alpha channel data. + /// Indicates, if the alpha data is compressed. + public void WriteTrunksBeforeData( + Stream stream, + uint width, + uint height, + ExifProfile? exifProfile, + XmpProfile? xmpProfile, + IccProfile? iccProfile, + bool hasAlpha, + Span alphaData, + bool alphaDataIsCompressed) + { + // Write file size later + this.WriteRiffHeader(stream, 0); + + // Write VP8X, header if necessary. + bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha; + if (isVp8X) + { + this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); + + if (iccProfile != null) + { + this.WriteColorProfile(stream, iccProfile.ToByteArray()); + } + + if (hasAlpha) + { + this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed); + } + } + } + + /// + /// Writes the encoded image to the stream. + /// + /// The stream to write to. + public abstract void WriteEncodedImageToStream(Stream stream); + + /// + /// Write the trunks after data trunk. + /// + /// Think of it as a static method — none of the other members are called except for + /// The stream to write to. + /// The exif profile. + /// The XMP profile. + public void WriteTrunksAfterData( + Stream stream, + ExifProfile? exifProfile, + XmpProfile? xmpProfile) + { + if (exifProfile != null) + { + this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); + } + + if (xmpProfile != null) + { + this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); + } + + OverwriteFileSize(stream); + } + /// /// Writes a metadata profile (EXIF or XMP) to the stream. /// diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs index 5dd5d335de..923d2a69c4 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs @@ -3,9 +3,6 @@ using System.Buffers.Binary; using SixLabors.ImageSharp.Formats.Webp.Lossy; -using SixLabors.ImageSharp.Metadata.Profiles.Exif; -using SixLabors.ImageSharp.Metadata.Profiles.Icc; -using SixLabors.ImageSharp.Metadata.Profiles.Xmp; namespace SixLabors.ImageSharp.Formats.Webp.BitWriter; @@ -394,56 +391,8 @@ internal class Vp8BitWriter : BitWriterBase } } - /// - /// Write the trunks before data trunk. - /// - /// Think of it as a static method — none of the other members are called except for - /// The stream to write to. - /// The width of the image. - /// The height of the image. - /// The exif profile. - /// The XMP profile. - /// The color profile. - /// Flag indicating, if a alpha channel is present. - /// The alpha channel data. - /// Indicates, if the alpha data is compressed. - public void WriteTrunksBeforeData( - Stream stream, - uint width, - uint height, - ExifProfile? exifProfile, - XmpProfile? xmpProfile, - IccProfile? iccProfile, - bool hasAlpha, - Span alphaData, - bool alphaDataIsCompressed) - { - // Write file size later - this.WriteRiffHeader(stream, 0); - - // Write VP8X, header if necessary. - bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha; - if (isVp8X) - { - this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); - - if (iccProfile != null) - { - this.WriteColorProfile(stream, iccProfile.ToByteArray()); - } - - if (hasAlpha) - { - this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed); - } - } - } - - /// - /// Writes the encoded image to the stream. - /// - /// The stream to write to. - public void WriteEncodedImageToStream(Stream stream) + /// + public override void WriteEncodedImageToStream(Stream stream) { uint numBytes = (uint)this.NumBytes; @@ -474,31 +423,6 @@ internal class Vp8BitWriter : BitWriterBase } } - /// - /// Write the trunks after data trunk. - /// - /// Think of it as a static method — none of the other members are called except for - /// The stream to write to. - /// The exif profile. - /// The XMP profile. - public void WriteTrunksAfterData( - Stream stream, - ExifProfile? exifProfile, - XmpProfile? xmpProfile) - { - if (exifProfile != null) - { - this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); - } - - if (xmpProfile != null) - { - this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); - } - - OverwriteFileSize(stream); - } - private uint GeneratePartition0() { this.PutBitUniform(0); // colorspace diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs index 0ac1b4038a..bce77c9e5c 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs @@ -3,9 +3,6 @@ using System.Buffers.Binary; using SixLabors.ImageSharp.Formats.Webp.Lossless; -using SixLabors.ImageSharp.Metadata.Profiles.Exif; -using SixLabors.ImageSharp.Metadata.Profiles.Icc; -using SixLabors.ImageSharp.Metadata.Profiles.Xmp; namespace SixLabors.ImageSharp.Formats.Webp.BitWriter; @@ -122,68 +119,11 @@ internal class Vp8LBitWriter : BitWriterBase this.used = 0; } - /// - /// Writes the encoded image to the stream. - /// - /// The stream to write to. - /// The exif profile. - /// The XMP profile. - /// The color profile. - /// The width of the image. - /// The height of the image. - /// Flag indicating, if a alpha channel is present. - public void WriteEncodedImageToStream(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha) + /// + public override void WriteEncodedImageToStream(Stream stream) { - bool isVp8X = false; - byte[]? exifBytes = null; - byte[]? xmpBytes = null; - byte[]? iccBytes = null; - uint riffSize = 0; - if (exifProfile != null) - { - isVp8X = true; - exifBytes = exifProfile.ToByteArray(); - riffSize += MetadataChunkSize(exifBytes!); - } - - if (xmpProfile != null) - { - isVp8X = true; - xmpBytes = xmpProfile.Data; - riffSize += MetadataChunkSize(xmpBytes!); - } - - if (iccProfile != null) - { - isVp8X = true; - iccBytes = iccProfile.ToByteArray(); - riffSize += MetadataChunkSize(iccBytes); - } - - if (isVp8X) - { - riffSize += ExtendedFileChunkSize; - } - - this.Finish(); - uint size = (uint)this.NumBytes; - size++; // One byte extra for the VP8L signature. - - // Write RIFF header. + uint size = (uint)this.NumBytes + 1; // One byte extra for the VP8L signature uint pad = size & 1; - riffSize += WebpConstants.TagSize + WebpConstants.ChunkHeaderSize + size + pad; - this.WriteRiffHeader(stream, riffSize); - - // Write VP8X, header if necessary. - if (isVp8X) - { - this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); - - if (iccBytes != null) - { - this.WriteColorProfile(stream, iccBytes); - } - } // Write magic bytes indicating its a lossless webp. Span scratchBuffer = stackalloc byte[WebpConstants.TagSize]; @@ -201,16 +141,6 @@ internal class Vp8LBitWriter : BitWriterBase { stream.WriteByte(0); } - - if (exifProfile != null) - { - this.WriteMetadataProfile(stream, exifBytes, WebpChunkType.Exif); - } - - if (xmpProfile != null) - { - this.WriteMetadataProfile(stream, xmpBytes, WebpChunkType.Xmp); - } } /// diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index d27bfcd956..4d526e7b4b 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -10,6 +10,7 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; using SixLabors.ImageSharp.PixelFormats; @@ -265,8 +266,22 @@ internal class Vp8LEncoder : IDisposable // Encode the main image stream. this.EncodeStream(image.Frames.RootFrame); + this.bitWriter.Finish(); + this.bitWriter.WriteTrunksBeforeData( + stream, + (uint)width, + (uint)height, + exifProfile, + xmpProfile, + metadata.IccProfile, + false /*hasAlpha*/, + Span.Empty, + false); + // Write bytes from the bitwriter buffer to the stream. - this.bitWriter.WriteEncodedImageToStream(stream, exifProfile, xmpProfile, metadata.IccProfile, (uint)width, (uint)height, hasAlpha); + this.bitWriter.WriteEncodedImageToStream(stream); + + this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile); } /// diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 56397e66d4..f744827bf3 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -8,7 +8,6 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; -using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; using SixLabors.ImageSharp.PixelFormats; From fbc08bd6a683a8c96777dfc17441d3fabb7f554c Mon Sep 17 00:00:00 2001 From: Poker Date: Mon, 23 Oct 2023 23:21:11 +0800 Subject: [PATCH 012/219] Implement Vp8 encoder --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 106 +++++++-------- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 5 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 121 ++++++++++++++---- .../Formats/Webp/WebpEncoderCore.cs | 30 ++++- .../Formats/WebP/WebpEncoderTests.cs | 7 + 5 files changed, 180 insertions(+), 89 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index ad7d69f130..4a9da3cbb1 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -87,21 +87,20 @@ internal abstract class BitWriterBase /// /// Writes the RIFF header to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The block length. - protected void WriteRiffHeader(Stream stream, uint riffSize) + protected static void WriteRiffHeader(Stream stream, uint riffSize) { stream.Write(WebpConstants.RiffFourCc); - BinaryPrimitives.WriteUInt32LittleEndian(this.scratchBuffer.Span, riffSize); - stream.Write(this.scratchBuffer.Span[..4]); + Span buf = stackalloc byte[4]; + BinaryPrimitives.WriteUInt32LittleEndian(buf, riffSize); + stream.Write(buf); stream.Write(WebpConstants.WebpHeader); } /// /// Calculates the chunk size of EXIF, XMP or ICCP metadata. /// - /// Think of it as a static method — none of the other members are called except for /// The metadata profile bytes. /// The metadata chunk size in bytes. protected static uint MetadataChunkSize(byte[] metadataBytes) @@ -125,22 +124,11 @@ internal abstract class BitWriterBase /// Overwrites ides the write file size. /// /// The stream to write to. - protected static void OverwriteFileSize(Stream stream) - { - uint position = (uint)stream.Position; - stream.Position = 4; - byte[] buffer = new byte[4]; - - // "RIFF"(4)+uint32 size(4) - BinaryPrimitives.WriteUInt32LittleEndian(buffer, position - WebpConstants.ChunkHeaderSize); - stream.Write(buffer); - stream.Position = position; - } + protected static void OverwriteFileSize(Stream stream) => OverwriteFrameSize(stream, 4); /// /// Write the trunks before data trunk. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The width of the image. /// The height of the image. @@ -148,9 +136,8 @@ internal abstract class BitWriterBase /// The XMP profile. /// The color profile. /// Flag indicating, if a alpha channel is present. - /// The alpha channel data. - /// Indicates, if the alpha data is compressed. - public void WriteTrunksBeforeData( + /// Flag indicating, if an animation parameter is present. + public static void WriteTrunksBeforeData( Stream stream, uint width, uint height, @@ -158,26 +145,20 @@ internal abstract class BitWriterBase XmpProfile? xmpProfile, IccProfile? iccProfile, bool hasAlpha, - Span alphaData, - bool alphaDataIsCompressed) + bool hasAnimation) { // Write file size later - this.WriteRiffHeader(stream, 0); + WriteRiffHeader(stream, 0); // Write VP8X, header if necessary. - bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha; + bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha || hasAnimation; if (isVp8X) { - this.WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha); + WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha, hasAnimation); if (iccProfile != null) { - this.WriteColorProfile(stream, iccProfile.ToByteArray()); - } - - if (hasAlpha) - { - this.WriteAlphaChunk(stream, alphaData, alphaDataIsCompressed); + WriteColorProfile(stream, iccProfile.ToByteArray()); } } } @@ -191,23 +172,22 @@ internal abstract class BitWriterBase /// /// Write the trunks after data trunk. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The exif profile. /// The XMP profile. - public void WriteTrunksAfterData( + public static void WriteTrunksAfterData( Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile) { if (exifProfile != null) { - this.WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); + WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); } if (xmpProfile != null) { - this.WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); + WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); } OverwriteFileSize(stream); @@ -216,16 +196,15 @@ internal abstract class BitWriterBase /// /// Writes a metadata profile (EXIF or XMP) to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The metadata profile's bytes. /// The chuck type to write. - protected void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpChunkType chunkType) + protected static void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpChunkType chunkType) { DebugGuard.NotNull(metadataBytes, nameof(metadataBytes)); uint size = (uint)metadataBytes.Length; - Span buf = this.scratchBuffer.Span[..4]; + Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)chunkType); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, size); @@ -242,15 +221,13 @@ internal abstract class BitWriterBase /// /// Writes the color profile() to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The color profile bytes. - protected void WriteColorProfile(Stream stream, byte[] iccProfileBytes) => this.WriteMetadataProfile(stream, iccProfileBytes, WebpChunkType.Iccp); + protected static void WriteColorProfile(Stream stream, byte[] iccProfileBytes) => WriteMetadataProfile(stream, iccProfileBytes, WebpChunkType.Iccp); /// /// Writes the animation parameter() to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// /// The default background color of the canvas in [Blue, Green, Red, Alpha] byte order. @@ -259,9 +236,9 @@ internal abstract class BitWriterBase /// The background color is also used when the Disposal method is 1. /// /// The number of times to loop the animation. If it is 0, this means infinitely. - protected void WriteAnimationParameter(Stream stream, uint background, ushort loopCount) + public static void WriteAnimationParameter(Stream stream, uint background, ushort loopCount) { - Span buf = this.scratchBuffer.Span[..4]; + Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.AnimationParameter); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, sizeof(uint) + sizeof(ushort)); @@ -275,17 +252,15 @@ internal abstract class BitWriterBase /// /// Writes the animation frame() to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// Animation frame data. - /// Frame data. - protected void WriteAnimationFrame(Stream stream, AnimationFrameData animation, Span data) + public static long WriteAnimationFrame(Stream stream, AnimationFrameData animation) { - uint size = AnimationFrameData.HeaderSize + (uint)data.Length; - Span buf = this.scratchBuffer.Span[..4]; + Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation); stream.Write(buf); - BinaryPrimitives.WriteUInt32BigEndian(buf, size); + long position = stream.Position; + BinaryPrimitives.WriteUInt32BigEndian(buf, 0); stream.Write(buf); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.X); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Y); @@ -294,20 +269,35 @@ internal abstract class BitWriterBase WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration); byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod); stream.WriteByte(flag); - stream.Write(data); + return position; + } + + /// + /// Overwrites ides the write frame size. + /// + /// The stream to write to. + /// Previous position. + public static void OverwriteFrameSize(Stream stream, long prevPosition) + { + uint position = (uint)stream.Position; + stream.Position = prevPosition; + byte[] buffer = new byte[4]; + + BinaryPrimitives.WriteUInt32LittleEndian(buffer, (uint)(position - prevPosition - 4)); + stream.Write(buffer); + stream.Position = position; } /// /// Writes the alpha chunk to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// The alpha channel data bytes. /// Indicates, if the alpha channel data is compressed. - protected void WriteAlphaChunk(Stream stream, Span dataBytes, bool alphaDataIsCompressed) + public static void WriteAlphaChunk(Stream stream, Span dataBytes, bool alphaDataIsCompressed) { uint size = (uint)dataBytes.Length + 1; - Span buf = this.scratchBuffer.Span[..4]; + Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Alpha); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, size); @@ -332,7 +322,6 @@ internal abstract class BitWriterBase /// /// Writes a VP8X header to the stream. /// - /// Think of it as a static method — none of the other members are called except for /// The stream to write to. /// A exif profile or null, if it does not exist. /// A XMP profile or null, if it does not exist. @@ -340,7 +329,8 @@ internal abstract class BitWriterBase /// The width of the image. /// The height of the image. /// Flag indicating, if a alpha channel is present. - protected void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha) + /// Flag indicating, if an animation parameter is present. + protected static void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) { if (width > MaxDimension || height > MaxDimension) { @@ -360,13 +350,11 @@ internal abstract class BitWriterBase flags |= 8; } - /* - if (isAnimated) + if (hasAnimation) { // Set animated flag. flags |= 2; } - */ if (xmpProfile != null) { @@ -386,7 +374,7 @@ internal abstract class BitWriterBase flags |= 32; } - Span buf = this.scratchBuffer.Span[..4]; + Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Vp8X); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, WebpConstants.Vp8XChunkSize); diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 4d526e7b4b..5859d8a872 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -267,7 +267,7 @@ internal class Vp8LEncoder : IDisposable this.EncodeStream(image.Frames.RootFrame); this.bitWriter.Finish(); - this.bitWriter.WriteTrunksBeforeData( + BitWriterBase.WriteTrunksBeforeData( stream, (uint)width, (uint)height, @@ -275,13 +275,12 @@ internal class Vp8LEncoder : IDisposable xmpProfile, metadata.IccProfile, false /*hasAlpha*/, - Span.Empty, false); // Write bytes from the bitwriter buffer to the stream. this.bitWriter.WriteEncodedImageToStream(stream); - this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); } /// diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index f744827bf3..ccd7d8b6d5 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -88,7 +88,8 @@ internal class Vp8Encoder : IDisposable private const ulong Partition0SizeLimit = (WebpConstants.Vp8MaxPartition0Size - 2048UL) << 11; - private const long HeaderSizeEstimate = WebpConstants.RiffHeaderSize + WebpConstants.ChunkHeaderSize + WebpConstants.Vp8FrameHeaderSize; + private const long HeaderSizeEstimate = + WebpConstants.RiffHeaderSize + WebpConstants.ChunkHeaderSize + WebpConstants.Vp8FrameHeaderSize; private const int QMin = 0; @@ -165,7 +166,7 @@ internal class Vp8Encoder : IDisposable // TODO: make partition_limit configurable? const int limit = 100; // original code: limit = 100 - config->partition_limit; this.maxI4HeaderBits = - 256 * 16 * 16 * limit * limit / (100 * 100); // ... modulated with a quadratic curve. + 256 * 16 * 16 * limit * limit / (100 * 100); // ... modulated with a quadratic curve. this.MbInfo = new Vp8MacroBlockInfo[this.Mbw * this.Mbh]; for (int i = 0; i < this.MbInfo.Length; i++) @@ -308,22 +309,88 @@ internal class Vp8Encoder : IDisposable /// private int MbHeaderLimit { get; } + public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation, uint background = 0, uint loopCount = 0) + where TPixel : unmanaged, IPixel + { + // Write bytes from the bitwriter buffer to the stream. + ImageMetadata metadata = image.Metadata; + metadata.SyncProfiles(); + + ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; + XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; + + BitWriterBase.WriteTrunksBeforeData( + stream, + (uint)image.Width, + (uint)image.Height, + exifProfile, + xmpProfile, + metadata.IccProfile, + hasAlpha, + hasAnimation); + + if (hasAnimation) + { + BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount); + } + } + + public void EncodeFooter(Image image, Stream stream) + where TPixel : unmanaged, IPixel + { + // Write bytes from the bitwriter buffer to the stream. + ImageMetadata metadata = image.Metadata; + + ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; + XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; + + BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + } + + /// + /// Encodes the image to the specified stream from the . + /// + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + public void EncodeAnimation(ImageFrame frame, Stream stream) + where TPixel : unmanaged, IPixel => + this.Encode(frame, stream, true, null); + /// /// Encodes the image to the specified stream from the . /// /// The pixel format. /// The to encode from. /// The to encode the image data to. - public void Encode(Image image, Stream stream) + public void EncodeStatic(Image image, Stream stream) + where TPixel : unmanaged, IPixel => + this.Encode(image.Frames.RootFrame, stream, false, image); + + /// + /// Encodes the image to the specified stream from the . + /// + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// Flag indicating, if an animation parameter is present. + /// The to encode from. + private void Encode(ImageFrame frame, Stream stream, bool hasAnimation, Image image) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; + int width = frame.Width; + int height = frame.Height; + int pixelCount = width * height; Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - bool hasAlpha = YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, this.configuration, this.memoryAllocator, y, u, v); + bool hasAlpha = YuvConversion.ConvertRgbToYuv(frame, this.configuration, this.memoryAllocator, y, u, v); + + if (!hasAnimation) + { + this.EncodeHeader(image, stream, hasAlpha, false); + } int yStride = width; int uvStride = (yStride + 1) >> 1; @@ -375,13 +442,6 @@ internal class Vp8Encoder : IDisposable // Store filter stats. this.AdjustFilterStrength(); - // Write bytes from the bitwriter buffer to the stream. - ImageMetadata metadata = image.Metadata; - metadata.SyncProfiles(); - - ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; - XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - // Extract and encode alpha channel data, if present. int alphaDataSize = 0; bool alphaCompressionSucceeded = false; @@ -393,7 +453,7 @@ internal class Vp8Encoder : IDisposable { // TODO: This can potentially run in an separate task. encodedAlphaData = AlphaEncoder.EncodeAlpha( - image.Frames.RootFrame, + frame, this.configuration, this.memoryAllocator, this.skipMetadata, @@ -409,20 +469,31 @@ internal class Vp8Encoder : IDisposable } this.bitWriter.Finish(); - this.bitWriter.WriteTrunksBeforeData( - stream, - (uint)width, - (uint)height, - exifProfile, - xmpProfile, - metadata.IccProfile, - hasAlpha, - alphaData[..alphaDataSize], - this.alphaCompression && alphaCompressionSucceeded); + + long prevPosition = 0; + + if (hasAnimation) + { + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() + { + Width = (uint)frame.Width, + Height = (uint)frame.Height + }); + } + + if (hasAlpha) + { + Span data = alphaData[..alphaDataSize]; + bool alphaDataIsCompressed = this.alphaCompression && alphaCompressionSucceeded; + BitWriterBase.WriteAlphaChunk(stream, data, alphaDataIsCompressed); + } this.bitWriter.WriteEncodedImageToStream(stream); - this.bitWriter.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + if (hasAnimation) + { + BitWriterBase.OverwriteFrameSize(stream, prevPosition); + } } finally { diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 49512e03b5..2751f99134 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -144,7 +144,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals } else { - using Vp8Encoder enc = new( + using Vp8Encoder encoder = new( this.memoryAllocator, this.configuration, image.Width, @@ -156,7 +156,33 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.filterStrength, this.spatialNoiseShaping, this.alphaCompression); - enc.Encode(image, stream); + if (image.Frames.Count > 1) + { + encoder.EncodeHeader(image, stream, false, true); + + foreach (ImageFrame imageFrame in image.Frames) + { + using Vp8Encoder enc = new( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.entropyPasses, + this.filterStrength, + this.spatialNoiseShaping, + this.alphaCompression); + enc.EncodeAnimation(imageFrame, stream); + } + } + else + { + encoder.EncodeStatic(image, stream); + } + + encoder.EncodeFooter(image, stream); } } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 6c5fa50ff6..4b100e854e 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -17,6 +17,13 @@ public class WebpEncoderTests { private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.NoFilter06); + [Fact] + public void Encode_AnimatedLossy() + { + Image image = Image.Load(@"C:\Users\poker\Desktop\1.webp"); + image.SaveAsWebp(@"C:\Users\poker\Desktop\3.webp"); + } + [Theory] [WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossy)] // If its not a webp input image, it should default to lossy. [WithFile(Lossless.NoTransform1, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] From 87de52141219f23a39559a8bae09d79c30e109d6 Mon Sep 17 00:00:00 2001 From: Poker Date: Mon, 23 Oct 2023 23:58:56 +0800 Subject: [PATCH 013/219] Implement Vp8L encoder --- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 87 +++++++++++++------ .../Formats/Webp/WebpEncoderCore.cs | 32 ++++++- .../Formats/WebP/WebpEncoderTests.cs | 7 +- 3 files changed, 97 insertions(+), 29 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 5859d8a872..d301df94f6 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -10,7 +10,6 @@ using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; -using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; using SixLabors.ImageSharp.PixelFormats; @@ -236,26 +235,59 @@ internal class Vp8LEncoder : IDisposable /// public Vp8LHashChain HashChain { get; } - /// - /// Encodes the image as lossless webp to the specified stream. - /// - /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - public void Encode(Image image, Stream stream) + public void EncodeHeader(Image image, Stream stream, bool hasAnimation, uint background = 0, uint loopCount = 0) where TPixel : unmanaged, IPixel { - int width = image.Width; - int height = image.Height; - + // Write bytes from the bitwriter buffer to the stream. ImageMetadata metadata = image.Metadata; metadata.SyncProfiles(); ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; + BitWriterBase.WriteTrunksBeforeData( + stream, + (uint)image.Width, + (uint)image.Height, + exifProfile, + xmpProfile, + metadata.IccProfile, + false, + hasAnimation); + + if (hasAnimation) + { + BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount); + } + } + + public void EncodeFooter(Image image, Stream stream) + where TPixel : unmanaged, IPixel + { + // Write bytes from the bitwriter buffer to the stream. + ImageMetadata metadata = image.Metadata; + + ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; + XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; + + BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + } + + /// + /// Encodes the image as lossless webp to the specified stream. + /// + /// The pixel format. + /// The to encode from. + /// The to encode the image data to. + /// Flag indicating, if an animation parameter is present. + public void Encode(ImageFrame frame, Stream stream, bool hasAnimation) + where TPixel : unmanaged, IPixel + { + int width = frame.Width; + int height = frame.Height; + // Convert image pixels to bgra array. - bool hasAlpha = this.ConvertPixelsToBgra(image.Frames.RootFrame, width, height); + bool hasAlpha = this.ConvertPixelsToBgra(frame, width, height); // Write the image size. this.WriteImageSize(width, height); @@ -264,23 +296,28 @@ internal class Vp8LEncoder : IDisposable this.WriteAlphaAndVersion(hasAlpha); // Encode the main image stream. - this.EncodeStream(image.Frames.RootFrame); + this.EncodeStream(frame); this.bitWriter.Finish(); - BitWriterBase.WriteTrunksBeforeData( - stream, - (uint)width, - (uint)height, - exifProfile, - xmpProfile, - metadata.IccProfile, - false /*hasAlpha*/, - false); + + long prevPosition = 0; + + if (hasAnimation) + { + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() + { + Width = (uint)frame.Width, + Height = (uint)frame.Height + }); + } // Write bytes from the bitwriter buffer to the stream. this.bitWriter.WriteEncodedImageToStream(stream); - BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + if (hasAnimation) + { + BitWriterBase.OverwriteFrameSize(stream, prevPosition); + } } /// @@ -1843,9 +1880,9 @@ internal class Vp8LEncoder : IDisposable { this.Bgra.Dispose(); this.EncodedData.Dispose(); - this.BgraScratch.Dispose(); + this.BgraScratch?.Dispose(); this.Palette.Dispose(); - this.TransformData.Dispose(); + this.TransformData?.Dispose(); this.HashChain.Dispose(); } diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 2751f99134..47712071bf 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -129,7 +129,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals if (lossless) { - using Vp8LEncoder enc = new( + using Vp8LEncoder encoder = new( this.memoryAllocator, this.configuration, image.Width, @@ -140,7 +140,34 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.transparentColorMode, this.nearLossless, this.nearLosslessQuality); - enc.Encode(image, stream); + + bool hasAnimation = image.Frames.Count > 1; + encoder.EncodeHeader(image, stream, hasAnimation); + if (hasAnimation) + { + foreach (ImageFrame imageFrame in image.Frames) + { + using Vp8LEncoder enc = new( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.transparentColorMode, + this.nearLossless, + this.nearLosslessQuality); + + enc.Encode(imageFrame, stream, true); + } + } + else + { + encoder.Encode(image.Frames.RootFrame, stream, false); + } + + encoder.EncodeFooter(image, stream); } else { @@ -174,6 +201,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.filterStrength, this.spatialNoiseShaping, this.alphaCompression); + enc.EncodeAnimation(imageFrame, stream); } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 4b100e854e..1721cd938b 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -20,8 +20,11 @@ public class WebpEncoderTests [Fact] public void Encode_AnimatedLossy() { - Image image = Image.Load(@"C:\Users\poker\Desktop\1.webp"); - image.SaveAsWebp(@"C:\Users\poker\Desktop\3.webp"); + Image image = Image.Load(@"C:\WorkSpace\ImageSharp\tests\Images\Input\Webp\leo_animated_lossless.webp"); + image.SaveAsWebp(@"C:\Users\poker\Desktop\3.webp", new WebpEncoder() + { + FileFormat = WebpFileFormatType.Lossless + }); } [Theory] From 2c260b27bf273f7154a93a43bf1e5149776fbe5d Mon Sep 17 00:00:00 2001 From: Poker Date: Tue, 24 Oct 2023 00:09:10 +0800 Subject: [PATCH 014/219] add unit test and format --- .../Formats/Webp/BitWriter/Vp8LBitWriter.cs | 6 ++-- .../Formats/WebP/WebpEncoderTests.cs | 29 ++++++++++++++----- 2 files changed, 25 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs index bce77c9e5c..0b71a3ed0c 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs @@ -44,9 +44,6 @@ internal class Vp8LBitWriter : BitWriterBase { } - /// - public override int NumBytes => this.cur + ((this.used + 7) >> 3); - /// /// Initializes a new instance of the class. /// Used internally for cloning. @@ -59,6 +56,9 @@ internal class Vp8LBitWriter : BitWriterBase this.cur = cur; } + /// + public override int NumBytes => this.cur + ((this.used + 7) >> 3); + /// /// This function writes bits into bytes in increasing addresses (little endian), /// and within a byte least-significant-bit first. This function can write up to 32 bits in one go. diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 1721cd938b..d81c9eb93a 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -17,14 +18,28 @@ public class WebpEncoderTests { private static string TestImageLossyFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, Lossy.NoFilter06); - [Fact] - public void Encode_AnimatedLossy() + [Theory] + [WithFile(Lossless.Animated, PixelTypes.Rgba32)] + public void Encode_AnimatedLossless(TestImageProvider provider) + where TPixel : unmanaged, IPixel { - Image image = Image.Load(@"C:\WorkSpace\ImageSharp\tests\Images\Input\Webp\leo_animated_lossless.webp"); - image.SaveAsWebp(@"C:\Users\poker\Desktop\3.webp", new WebpEncoder() - { - FileFormat = WebpFileFormatType.Lossless - }); + using Image image = provider.GetImage(); + using MemoryStream memStream = new(); + image.SaveAsWebp(memStream, new() { FileFormat = WebpFileFormatType.Lossless }); + + // TODO: DebugSave, VerifySimilarity + } + + [Theory] + [WithFile(Lossy.Animated, PixelTypes.Rgba32)] + public void Encode_AnimatedLossy(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + using MemoryStream memStream = new(); + image.SaveAsWebp(memStream, new()); + + // TODO: DebugSave, VerifySimilarity } [Theory] From 6fed95b5165f4216d9cb476d54fbd3e7faf5f59b Mon Sep 17 00:00:00 2001 From: Poker Date: Tue, 24 Oct 2023 09:03:23 +0800 Subject: [PATCH 015/219] remove unused scratchBuffer field --- src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 4a9da3cbb1..89db7ed645 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -22,11 +22,6 @@ internal abstract class BitWriterBase /// private byte[] buffer; - /// - /// A scratch buffer to reduce allocations. - /// - private ScratchBuffer scratchBuffer; // mutable struct, don't make readonly - /// /// Initializes a new instance of the class. /// From dbb89603ee4ac639f8b6fa08fde747250b10d7b5 Mon Sep 17 00:00:00 2001 From: Poker Date: Tue, 24 Oct 2023 12:38:17 +0800 Subject: [PATCH 016/219] encode FrameDuration --- src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs | 3 ++- src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index d301df94f6..af472845ac 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -307,7 +307,8 @@ internal class Vp8LEncoder : IDisposable prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() { Width = (uint)frame.Width, - Height = (uint)frame.Height + Height = (uint)frame.Height, + Duration = frame.Metadata.GetWebpMetadata().FrameDuration }); } diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index ccd7d8b6d5..40dbb90de6 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -477,7 +477,8 @@ internal class Vp8Encoder : IDisposable prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() { Width = (uint)frame.Width, - Height = (uint)frame.Height + Height = (uint)frame.Height, + Duration = frame.Metadata.GetWebpMetadata().FrameDuration }); } From bd2d4550a998bb521cc8cce39bad9be42da201bf Mon Sep 17 00:00:00 2001 From: Poker Date: Wed, 25 Oct 2023 16:47:14 +0800 Subject: [PATCH 017/219] refactor to follow style rules --- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 2 +- src/ImageSharp/Formats/Webp/AlphaEncoder.cs | 17 ++---- .../Formats/Webp/AnimationFrameData.cs | 2 +- .../Formats/Webp/BitWriter/Vp8BitWriter.cs | 4 +- .../Formats/Webp/BitWriter/Vp8LBitWriter.cs | 2 +- .../Webp/Lossless/BackwardReferenceEncoder.cs | 2 +- .../Formats/Webp/Lossless/CostManager.cs | 2 +- .../Formats/Webp/Lossless/PixOrCopy.cs | 7 ++- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 18 +++--- .../Webp/Lossless/WebpLosslessDecoder.cs | 4 +- .../Formats/Webp/Lossy/Vp8EncIterator.cs | 6 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 16 ++--- .../Formats/Webp/Lossy/WebpLossyDecoder.cs | 18 +++--- .../Formats/Webp/WebpAnimationDecoder.cs | 12 ++-- .../Formats/Webp/WebpAnimationEncoder.cs | 12 ---- .../Formats/Webp/WebpChunkParsingUtils.cs | 20 ++++--- src/ImageSharp/Formats/Webp/WebpDecoder.cs | 9 ++- .../Formats/Webp/WebpDecoderCore.cs | 27 +++++---- .../Formats/Webp/WebpDecoderOptions.cs | 2 +- src/ImageSharp/Formats/Webp/WebpEncoder.cs | 2 +- .../Formats/Webp/WebpEncoderCore.cs | 58 ++++--------------- src/ImageSharp/Formats/Webp/WebpFormat.cs | 6 +- 22 files changed, 99 insertions(+), 149 deletions(-) delete mode 100644 src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 289ebd35ca..63e6541354 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -59,7 +59,7 @@ internal class AlphaDecoder : IDisposable if (this.Compressed) { - Vp8LBitReader bitReader = new(data); + Vp8LBitReader bitReader = new Vp8LBitReader(data); this.LosslessDecoder = new WebpLosslessDecoder(bitReader, memoryAllocator, configuration); this.LosslessDecoder.DecodeImageStream(this.Vp8LDec, width, height, true); diff --git a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs index a18d44fde4..2084686969 100644 --- a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs @@ -43,17 +43,8 @@ internal static class AlphaEncoder { const WebpEncodingMethod effort = WebpEncodingMethod.Default; const int quality = 8 * (int)effort; - using Vp8LEncoder lossLessEncoder = new( - memoryAllocator, - configuration, - width, - height, - quality, - skipMetadata, - effort, - WebpTransparentColorMode.Preserve, - false, - 0); + using Vp8LEncoder lossLessEncoder = new Vp8LEncoder(memoryAllocator, configuration, width, height, quality, + skipMetadata, effort, WebpTransparentColorMode.Preserve, false, 0); // The transparency information will be stored in the green channel of the ARGB quadruplet. // The green channel is allowed extra transformation steps in the specification -- unlike the other channels, @@ -81,7 +72,7 @@ internal static class AlphaEncoder { int width = frame.Width; int height = frame.Height; - ImageFrame alphaAsFrame = new(Configuration.Default, width, height); + ImageFrame alphaAsFrame = new ImageFrame(Configuration.Default, width, height); for (int y = 0; y < height; y++) { @@ -91,7 +82,7 @@ internal static class AlphaEncoder for (int x = 0; x < width; x++) { // Leave A/R/B channels zero'd. - pixelRow[x] = new(0, alphaRow[x], 0, 0); + pixelRow[x] = new Rgba32(0, alphaRow[x], 0, 0); } } diff --git a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs b/src/ImageSharp/Formats/Webp/AnimationFrameData.cs index 3400fef17d..27a1815fe3 100644 --- a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs +++ b/src/ImageSharp/Formats/Webp/AnimationFrameData.cs @@ -62,7 +62,7 @@ internal struct AnimationFrameData { Span buffer = stackalloc byte[4]; - AnimationFrameData data = new() + AnimationFrameData data = new AnimationFrameData { DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer), diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs index 923d2a69c4..81530706d6 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8BitWriter.cs @@ -399,7 +399,7 @@ internal class Vp8BitWriter : BitWriterBase int mbSize = this.enc.Mbw * this.enc.Mbh; int expectedSize = (int)((uint)mbSize * 7 / 8); - Vp8BitWriter bitWriterPartZero = new(expectedSize, this.enc); + Vp8BitWriter bitWriterPartZero = new Vp8BitWriter(expectedSize, this.enc); // Partition #0 with header and partition sizes. uint size0 = bitWriterPartZero.GeneratePartition0(); @@ -545,7 +545,7 @@ internal class Vp8BitWriter : BitWriterBase // Writes the partition #0 modes (that is: all intra modes) private void CodeIntraModes() { - Vp8EncIterator it = new(this.enc); + Vp8EncIterator it = new Vp8EncIterator(this.enc); int predsWidth = this.enc.PredsWidth; do diff --git a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs index 0b71a3ed0c..dc867fa85e 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/Vp8LBitWriter.cs @@ -102,7 +102,7 @@ internal class Vp8LBitWriter : BitWriterBase { byte[] clonedBuffer = new byte[this.Buffer.Length]; System.Buffer.BlockCopy(this.Buffer, 0, clonedBuffer, 0, this.cur); - return new(clonedBuffer, this.bits, this.used, this.cur); + return new Vp8LBitWriter(clonedBuffer, this.bits, this.used, this.cur); } /// diff --git a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs index 61133142bf..03cb1990b9 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/BackwardReferenceEncoder.cs @@ -775,7 +775,7 @@ internal static class BackwardReferenceEncoder private static void BackwardRefsWithLocalCache(ReadOnlySpan bgra, int cacheBits, Vp8LBackwardRefs refs) { int pixelIndex = 0; - ColorCache colorCache = new(cacheBits); + ColorCache colorCache = new ColorCache(cacheBits); for (int idx = 0; idx < refs.Refs.Count; idx++) { PixOrCopy v = refs.Refs[idx]; diff --git a/src/ImageSharp/Formats/Webp/Lossless/CostManager.cs b/src/ImageSharp/Formats/Webp/Lossless/CostManager.cs index e393c065ec..63ce9dbec6 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/CostManager.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/CostManager.cs @@ -17,7 +17,7 @@ internal sealed class CostManager : IDisposable private const int FreeIntervalsStartCount = 25; - private readonly Stack freeIntervals = new(FreeIntervalsStartCount); + private readonly Stack freeIntervals = new Stack(FreeIntervalsStartCount); public CostManager(MemoryAllocator memoryAllocator, IMemoryOwner distArray, int pixCount, CostModel costModel) { diff --git a/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs b/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs index 6a28e5b3fb..61804812d5 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/PixOrCopy.cs @@ -15,7 +15,7 @@ internal sealed class PixOrCopy public uint BgraOrDistance { get; set; } public static PixOrCopy CreateCacheIdx(int idx) => - new() + new PixOrCopy { Mode = PixOrCopyMode.CacheIdx, BgraOrDistance = (uint)idx, @@ -23,14 +23,15 @@ internal sealed class PixOrCopy }; public static PixOrCopy CreateLiteral(uint bgra) => - new() + new PixOrCopy { Mode = PixOrCopyMode.Literal, BgraOrDistance = bgra, Len = 1 }; - public static PixOrCopy CreateCopy(uint distance, ushort len) => new() + public static PixOrCopy CreateCopy(uint distance, ushort len) => + new PixOrCopy { Mode = PixOrCopyMode.Copy, BgraOrDistance = distance, diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index af472845ac..3da27229ab 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -304,7 +304,7 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData { Width = (uint)frame.Width, Height = (uint)frame.Height, @@ -547,7 +547,7 @@ internal class Vp8LEncoder : IDisposable EntropyIx entropyIdx = this.AnalyzeEntropy(bgra, width, height, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero); bool doNotCache = false; - List crunchConfigs = new(); + List crunchConfigs = new List(); if (this.method == WebpEncodingMethod.BestQuality && this.quality == 100) { @@ -641,8 +641,8 @@ internal class Vp8LEncoder : IDisposable Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0]; this.bitWriter.Reset(bwInit); - Vp8LHistogram tmpHisto = new(cacheBits); - List histogramImage = new(histogramImageXySize); + Vp8LHistogram tmpHisto = new Vp8LHistogram(cacheBits); + List histogramImage = new List(histogramImageXySize); for (int i = 0; i < histogramImageXySize; i++) { histogramImage.Add(new Vp8LHistogram(cacheBits)); @@ -839,9 +839,9 @@ internal class Vp8LEncoder : IDisposable refsTmp1, refsTmp2); - List histogramImage = new() + List histogramImage = new List { - new(cacheBits) + new Vp8LHistogram(cacheBits) }; // Build histogram image and symbols from backward references. @@ -941,7 +941,7 @@ internal class Vp8LEncoder : IDisposable int i; byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes]; short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes]; - HuffmanTreeCode huffmanCode = new() + HuffmanTreeCode huffmanCode = new HuffmanTreeCode { NumSymbols = WebpConstants.CodeLengthCodes, CodeLengths = codeLengthBitDepth, @@ -1192,7 +1192,7 @@ internal class Vp8LEncoder : IDisposable histo[(int)HistoIx.HistoBluePred * 256]++; histo[(int)HistoIx.HistoAlphaPred * 256]++; - Vp8LBitEntropy bitEntropy = new(); + Vp8LBitEntropy bitEntropy = new Vp8LBitEntropy(); for (int j = 0; j < (int)HistoIx.HistoTotal; j++) { bitEntropy.Init(); @@ -1318,7 +1318,7 @@ internal class Vp8LEncoder : IDisposable /// The number of palette entries. private static int GetColorPalette(ReadOnlySpan bgra, int width, int height, Span palette) { - HashSet colors = new(); + HashSet colors = new HashSet(); for (int y = 0; y < height; y++) { ReadOnlySpan bgraRow = bgra.Slice(y * width, width); diff --git a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs index 19ea424199..54dd1d6ed1 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs @@ -95,7 +95,7 @@ internal sealed class WebpLosslessDecoder public void Decode(Buffer2D pixels, int width, int height) where TPixel : unmanaged, IPixel { - using (Vp8LDecoder decoder = new(width, height, this.memoryAllocator)) + using (Vp8LDecoder decoder = new Vp8LDecoder(width, height, this.memoryAllocator)) { this.DecodeImageStream(decoder, width, height, true); this.DecodeImageData(decoder, decoder.Pixels.Memory.Span); @@ -616,7 +616,7 @@ internal sealed class WebpLosslessDecoder private void ReadTransformation(int xSize, int ySize, Vp8LDecoder decoder) { Vp8LTransformType transformType = (Vp8LTransformType)this.bitReader.ReadValue(2); - Vp8LTransform transform = new(transformType, xSize, ySize); + Vp8LTransform transform = new Vp8LTransform(transformType, xSize, ySize); // Each transform is allowed to be used only once. foreach (Vp8LTransform decoderTransform in decoder.Transforms) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs index a7c96edb7c..52c7e9703b 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8EncIterator.cs @@ -396,7 +396,7 @@ internal class Vp8EncIterator this.MakeLuma16Preds(); for (mode = 0; mode < maxMode; mode++) { - Vp8Histogram histo = new(); + Vp8Histogram histo = new Vp8Histogram(); histo.CollectHistogram(this.YuvIn.AsSpan(YOffEnc), this.YuvP.AsSpan(Vp8Encoding.Vp8I16ModeOffsets[mode]), 0, 16); int alpha = histo.GetAlpha(); if (alpha > bestAlpha) @@ -414,7 +414,7 @@ internal class Vp8EncIterator { Span modes = stackalloc byte[16]; const int maxMode = MaxIntra4Mode; - Vp8Histogram totalHisto = new(); + Vp8Histogram totalHisto = new Vp8Histogram(); int curHisto = 0; this.StartI4(); do @@ -467,7 +467,7 @@ internal class Vp8EncIterator this.MakeChroma8Preds(); for (mode = 0; mode < maxMode; ++mode) { - Vp8Histogram histo = new(); + Vp8Histogram histo = new Vp8Histogram(); histo.CollectHistogram(this.YuvIn.AsSpan(UOffEnc), this.YuvP.AsSpan(Vp8Encoding.Vp8UvModeOffsets[mode]), 16, 16 + 4 + 4); int alpha = histo.GetAlpha(); if (alpha > bestAlpha) diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 40dbb90de6..e62eb6cfc3 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -395,7 +395,7 @@ internal class Vp8Encoder : IDisposable int yStride = width; int uvStride = (yStride + 1) >> 1; - Vp8EncIterator it = new(this); + Vp8EncIterator it = new Vp8EncIterator(this); Span alphas = stackalloc 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; @@ -416,8 +416,8 @@ internal class Vp8Encoder : IDisposable this.StatLoop(width, height, yStride, uvStride); it.Init(); Vp8EncIterator.InitFilter(); - Vp8ModeScore info = new(); - Vp8Residual residual = new(); + Vp8ModeScore info = new Vp8ModeScore(); + Vp8Residual residual = new Vp8Residual(); do { bool dontUseSkip = !this.Proba.UseSkipProba; @@ -474,7 +474,7 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new() + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData { Width = (uint)frame.Width, Height = (uint)frame.Height, @@ -529,7 +529,7 @@ internal class Vp8Encoder : IDisposable Vp8RdLevel rdOpt = this.method >= WebpEncodingMethod.Level3 || doSearch ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone; int nbMbs = this.Mbw * this.Mbh; - PassStats stats = new(targetSize, targetPsnr, QMin, QMax, this.quality); + PassStats stats = new PassStats(targetSize, targetPsnr, QMin, QMax, this.quality); this.Proba.ResetTokenStats(); // Fast mode: quick analysis pass over few mbs. Better than nothing. @@ -597,7 +597,7 @@ internal class Vp8Encoder : IDisposable Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - Vp8EncIterator it = new(this); + Vp8EncIterator it = new Vp8EncIterator(this); long size = 0; long sizeP0 = 0; long distortion = 0; @@ -605,7 +605,7 @@ internal class Vp8Encoder : IDisposable it.Init(); this.SetLoopParams(stats.Q); - Vp8ModeScore info = new(); + Vp8ModeScore info = new Vp8ModeScore(); do { info.Clear(); @@ -1167,7 +1167,7 @@ internal class Vp8Encoder : IDisposable private void RecordResiduals(Vp8EncIterator it, Vp8ModeScore rd) { int x, y, ch; - Vp8Residual residual = new(); + Vp8Residual residual = new Vp8Residual(); bool i16 = it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16; it.NzToBytes(); diff --git a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs index 7952b15b44..4ac516f055 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs @@ -62,7 +62,7 @@ internal sealed class WebpLossyDecoder // Paragraph 9.2: color space and clamp type follow. sbyte colorSpace = (sbyte)this.bitReader.ReadValue(1); sbyte clampType = (sbyte)this.bitReader.ReadValue(1); - Vp8PictureHeader pictureHeader = new() + Vp8PictureHeader pictureHeader = new Vp8PictureHeader { Width = (uint)width, Height = (uint)height, @@ -73,10 +73,11 @@ internal sealed class WebpLossyDecoder }; // Paragraph 9.3: Parse the segment header. - Vp8Proba proba = new(); + Vp8Proba proba = new Vp8Proba(); Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba); - using (Vp8Decoder decoder = new(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba, this.memoryAllocator)) + using (Vp8Decoder decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba, + this.memoryAllocator)) { Vp8Io io = InitializeVp8Io(decoder, pictureHeader); @@ -101,13 +102,8 @@ internal sealed class WebpLossyDecoder if (info.Features?.Alpha == true) { - using (AlphaDecoder alphaDecoder = new( - width, - height, - alphaData, - info.Features.AlphaChunkHeader, - this.memoryAllocator, - this.configuration)) + using (AlphaDecoder alphaDecoder = new AlphaDecoder(width, height, alphaData, + info.Features.AlphaChunkHeader, this.memoryAllocator, this.configuration)) { alphaDecoder.Decode(); DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); @@ -1062,7 +1058,7 @@ internal sealed class WebpLossyDecoder private Vp8SegmentHeader ParseSegmentHeader(Vp8Proba proba) { - Vp8SegmentHeader vp8SegmentHeader = new() + Vp8SegmentHeader vp8SegmentHeader = new Vp8SegmentHeader { UseSegment = this.bitReader.ReadBool() }; diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 81a7aebdf9..6922e37d6e 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -153,7 +153,7 @@ internal class WebpAnimationDecoder : IDisposable } WebpImageInfo? webpInfo = null; - WebpFeatures features = new(); + WebpFeatures features = new WebpFeatures(); switch (chunkType) { case WebpChunkType.Vp8: @@ -178,7 +178,7 @@ internal class WebpAnimationDecoder : IDisposable ImageFrame imageFrame; if (previousFrame is null) { - image = new(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata); + image = new Image(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata); SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData.Duration); @@ -259,19 +259,21 @@ internal class WebpAnimationDecoder : IDisposable private Buffer2D DecodeImageData(AnimationFrameData frameData, WebpImageInfo webpInfo) where TPixel : unmanaged, IPixel { - Image decodedImage = new((int)frameData.Width, (int)frameData.Height); + Image decodedImage = new Image((int)frameData.Width, (int)frameData.Height); try { Buffer2D pixelBufferDecoded = decodedImage.GetRootFramePixelBuffer(); if (webpInfo.IsLossless) { - WebpLosslessDecoder losslessDecoder = new(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); + WebpLosslessDecoder losslessDecoder = + new WebpLosslessDecoder(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); losslessDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height); } else { - WebpLossyDecoder lossyDecoder = new(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration); + WebpLossyDecoder lossyDecoder = + new WebpLossyDecoder(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration); lossyDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height, webpInfo, this.alphaData); } diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs deleted file mode 100644 index bfa64b6797..0000000000 --- a/src/ImageSharp/Formats/Webp/WebpAnimationEncoder.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Formats.Webp; - -/// -/// Encoder for animated webp images. -/// -public class WebpAnimationEncoder -{ - // 可能不需要这个屌东西 -} diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index 9e9f0f7f62..f4e40090cf 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -8,6 +8,8 @@ using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; +using SixLabors.ImageSharp.Metadata.Profiles.Xmp; namespace SixLabors.ImageSharp.Formats.Webp; @@ -104,16 +106,16 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowImageFormatException("bad partition length"); } - Vp8FrameHeader vp8FrameHeader = new() + Vp8FrameHeader vp8FrameHeader = new Vp8FrameHeader { KeyFrame = true, Profile = (sbyte)version, PartitionLength = partitionLength }; - Vp8BitReader bitReader = new(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; + Vp8BitReader bitReader = new Vp8BitReader(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; - return new() + return new WebpImageInfo { Width = width, Height = height, @@ -137,7 +139,7 @@ internal static class WebpChunkParsingUtils // VP8 data size. uint imageDataSize = ReadChunkSize(stream, buffer); - Vp8LBitReader bitReader = new(stream, imageDataSize, memoryAllocator); + Vp8LBitReader bitReader = new Vp8LBitReader(stream, imageDataSize, memoryAllocator); // One byte signature, should be 0x2f. uint signature = bitReader.ReadValue(8); @@ -166,7 +168,7 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowNotSupportedException($"Unexpected version number {version} found in VP8L header"); } - return new() + return new WebpImageInfo { Width = width, Height = height, @@ -229,7 +231,7 @@ internal static class WebpChunkParsingUtils uint height = ReadUInt24LittleEndian(stream, buffer) + 1; // Read all the chunks in the order they occur. - WebpImageInfo info = new() + WebpImageInfo info = new WebpImageInfo { Width = width, Height = height, @@ -291,7 +293,7 @@ internal static class WebpChunkParsingUtils if (stream.Read(buffer) == 4) { uint chunkSize = BinaryPrimitives.ReadUInt32LittleEndian(buffer); - return (chunkSize % 2 == 0) ? chunkSize : chunkSize + 1; + return chunkSize % 2 == 0 ? chunkSize : chunkSize + 1; } throw new ImageFormatException("Invalid Webp data, could not read chunk size."); @@ -348,7 +350,7 @@ internal static class WebpChunkParsingUtils if (metadata.ExifProfile != null) { - metadata.ExifProfile = new(exifData); + metadata.ExifProfile = new ExifProfile(exifData); } break; @@ -362,7 +364,7 @@ internal static class WebpChunkParsingUtils if (metadata.XmpProfile != null) { - metadata.XmpProfile = new(xmpData); + metadata.XmpProfile = new XmpProfile(xmpData); } break; diff --git a/src/ImageSharp/Formats/Webp/WebpDecoder.cs b/src/ImageSharp/Formats/Webp/WebpDecoder.cs index e23b817ccd..dfbf4ef0e6 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoder.cs @@ -17,7 +17,7 @@ public sealed class WebpDecoder : SpecializedImageDecoder /// /// Gets the shared instance. /// - public static WebpDecoder Instance { get; } = new(); + public static WebpDecoder Instance { get; } = new WebpDecoder(); /// protected override ImageInfo Identify(DecoderOptions options, Stream stream, CancellationToken cancellationToken) @@ -25,7 +25,7 @@ public sealed class WebpDecoder : SpecializedImageDecoder Guard.NotNull(options, nameof(options)); Guard.NotNull(stream, nameof(stream)); - using WebpDecoderCore decoder = new(new WebpDecoderOptions() { GeneralOptions = options }); + using WebpDecoderCore decoder = new WebpDecoderCore(new WebpDecoderOptions() { GeneralOptions = options }); return decoder.Identify(options.Configuration, stream, cancellationToken); } @@ -35,7 +35,7 @@ public sealed class WebpDecoder : SpecializedImageDecoder Guard.NotNull(options, nameof(options)); Guard.NotNull(stream, nameof(stream)); - using WebpDecoderCore decoder = new(options); + using WebpDecoderCore decoder = new WebpDecoderCore(options); Image image = decoder.Decode(options.GeneralOptions.Configuration, stream, cancellationToken); ScaleToTargetSize(options.GeneralOptions, image); @@ -52,6 +52,5 @@ public sealed class WebpDecoder : SpecializedImageDecoder => this.Decode(options, stream, cancellationToken); /// - protected override WebpDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) - => new() { GeneralOptions = options }; + protected override WebpDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new WebpDecoderOptions { GeneralOptions = options }; } diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 63d3e1aead..bb54d99a04 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -8,7 +8,9 @@ using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; +using SixLabors.ImageSharp.Metadata.Profiles.Xmp; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp; @@ -71,7 +73,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable public DecoderOptions Options { get; } /// - public Size Dimensions => new((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height); + public Size Dimensions => new Size((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height); /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) @@ -80,7 +82,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Image? image = null; try { - ImageMetadata metadata = new(); + ImageMetadata metadata = new ImageMetadata(); Span buffer = stackalloc byte[4]; uint fileSize = ReadImageHeader(stream, buffer); @@ -89,7 +91,8 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable { if (this.webImageInfo.Features is { Animation: true }) { - using WebpAnimationDecoder animationDecoder = new(this.memoryAllocator, this.configuration, this.maxFrames, this.backgroundColorHandling); + using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder(this.memoryAllocator, + this.configuration, this.maxFrames, this.backgroundColorHandling); return animationDecoder.Decode(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize); } @@ -97,12 +100,14 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.webImageInfo.IsLossless) { - WebpLosslessDecoder losslessDecoder = new(this.webImageInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); + WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder(this.webImageInfo.Vp8LBitReader, + this.memoryAllocator, this.configuration); losslessDecoder.Decode(pixels, image.Width, image.Height); } else { - WebpLossyDecoder lossyDecoder = new(this.webImageInfo.Vp8BitReader, this.memoryAllocator, this.configuration); + WebpLossyDecoder lossyDecoder = new WebpLossyDecoder(this.webImageInfo.Vp8BitReader, + this.memoryAllocator, this.configuration); lossyDecoder.Decode(pixels, image.Width, image.Height, this.webImageInfo, this.alphaData); } @@ -127,12 +132,12 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable { ReadImageHeader(stream, stackalloc byte[4]); - ImageMetadata metadata = new(); + ImageMetadata metadata = new ImageMetadata(); using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true)) { return new ImageInfo( new PixelTypeInfo((int)this.webImageInfo.BitsPerPixel), - new((int)this.webImageInfo.Width, (int)this.webImageInfo.Height), + new Size((int)this.webImageInfo.Width, (int)this.webImageInfo.Height), metadata); } } @@ -173,7 +178,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Span buffer = stackalloc byte[4]; WebpChunkType chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer); - WebpFeatures features = new(); + WebpFeatures features = new WebpFeatures(); switch (chunkType) { case WebpChunkType.Vp8: @@ -327,7 +332,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable return; } - metadata.ExifProfile = new(exifData); + metadata.ExifProfile = new ExifProfile(exifData); } } @@ -354,7 +359,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable return; } - metadata.XmpProfile = new(xmpData); + metadata.XmpProfile = new XmpProfile(xmpData); } } @@ -380,7 +385,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the iccp chunk"); } - IccProfile profile = new(iccpData); + IccProfile profile = new IccProfile(iccpData); if (profile.CheckIsValid()) { metadata.IccProfile = profile; diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs b/src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs index 6fb15acbb4..8840805b1f 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderOptions.cs @@ -9,7 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Webp; public sealed class WebpDecoderOptions : ISpecializedDecoderOptions { /// - public DecoderOptions GeneralOptions { get; init; } = new(); + public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions(); /// /// Gets the flag to decide how to handle the background color Animation Chunk. diff --git a/src/ImageSharp/Formats/Webp/WebpEncoder.cs b/src/ImageSharp/Formats/Webp/WebpEncoder.cs index 29d0c9e3b0..13c9798dbb 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoder.cs @@ -82,7 +82,7 @@ public sealed class WebpEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - WebpEncoderCore encoder = new(this, image.Configuration); + WebpEncoderCore encoder = new WebpEncoderCore(this, image.Configuration); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 47712071bf..dcff53f3af 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -129,17 +129,9 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals if (lossless) { - using Vp8LEncoder encoder = new( - this.memoryAllocator, - this.configuration, - image.Width, - image.Height, - this.quality, - this.skipMetadata, - this.method, - this.transparentColorMode, - this.nearLossless, - this.nearLosslessQuality); + using Vp8LEncoder encoder = new Vp8LEncoder(this.memoryAllocator, this.configuration, image.Width, + image.Height, this.quality, this.skipMetadata, this.method, this.transparentColorMode, + this.nearLossless, this.nearLosslessQuality); bool hasAnimation = image.Frames.Count > 1; encoder.EncodeHeader(image, stream, hasAnimation); @@ -147,17 +139,9 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals { foreach (ImageFrame imageFrame in image.Frames) { - using Vp8LEncoder enc = new( - this.memoryAllocator, - this.configuration, - image.Width, - image.Height, - this.quality, - this.skipMetadata, - this.method, - this.transparentColorMode, - this.nearLossless, - this.nearLosslessQuality); + using Vp8LEncoder enc = new Vp8LEncoder(this.memoryAllocator, this.configuration, image.Width, + image.Height, this.quality, this.skipMetadata, this.method, this.transparentColorMode, + this.nearLossless, this.nearLosslessQuality); enc.Encode(imageFrame, stream, true); } @@ -171,36 +155,18 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals } else { - using Vp8Encoder encoder = new( - this.memoryAllocator, - this.configuration, - image.Width, - image.Height, - this.quality, - this.skipMetadata, - this.method, - this.entropyPasses, - this.filterStrength, - this.spatialNoiseShaping, - this.alphaCompression); + using Vp8Encoder encoder = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, + image.Height, this.quality, this.skipMetadata, this.method, this.entropyPasses, this.filterStrength, + this.spatialNoiseShaping, this.alphaCompression); if (image.Frames.Count > 1) { encoder.EncodeHeader(image, stream, false, true); foreach (ImageFrame imageFrame in image.Frames) { - using Vp8Encoder enc = new( - this.memoryAllocator, - this.configuration, - image.Width, - image.Height, - this.quality, - this.skipMetadata, - this.method, - this.entropyPasses, - this.filterStrength, - this.spatialNoiseShaping, - this.alphaCompression); + using Vp8Encoder enc = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, + image.Height, this.quality, this.skipMetadata, this.method, this.entropyPasses, + this.filterStrength, this.spatialNoiseShaping, this.alphaCompression); enc.EncodeAnimation(imageFrame, stream); } diff --git a/src/ImageSharp/Formats/Webp/WebpFormat.cs b/src/ImageSharp/Formats/Webp/WebpFormat.cs index 29c74b11bf..197041234e 100644 --- a/src/ImageSharp/Formats/Webp/WebpFormat.cs +++ b/src/ImageSharp/Formats/Webp/WebpFormat.cs @@ -15,7 +15,7 @@ public sealed class WebpFormat : IImageFormat /// /// Gets the shared instance. /// - public static WebpFormat Instance { get; } = new(); + public static WebpFormat Instance { get; } = new WebpFormat(); /// public string Name => "Webp"; @@ -30,8 +30,8 @@ public sealed class WebpFormat : IImageFormat public IEnumerable FileExtensions => WebpConstants.FileExtensions; /// - public WebpMetadata CreateDefaultFormatMetadata() => new(); + public WebpMetadata CreateDefaultFormatMetadata() => new WebpMetadata(); /// - public WebpFrameMetadata CreateDefaultFormatFrameMetadata() => new(); + public WebpFrameMetadata CreateDefaultFormatFrameMetadata() => new WebpFrameMetadata(); } From d4483217b623aa751f5591d7edc93a7c812a91b2 Mon Sep 17 00:00:00 2001 From: Poker Date: Wed, 25 Oct 2023 19:48:07 +0800 Subject: [PATCH 018/219] fix SA1117 --- src/ImageSharp/Formats/Webp/AlphaEncoder.cs | 13 ++++- .../Formats/Webp/Lossy/WebpLossyDecoder.cs | 15 ++++- .../Formats/Webp/WebpDecoderCore.cs | 19 ++++-- .../Formats/Webp/WebpEncoderCore.cs | 58 +++++++++++++++---- 4 files changed, 82 insertions(+), 23 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs index 2084686969..cbd2aa8e7f 100644 --- a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs @@ -43,8 +43,17 @@ internal static class AlphaEncoder { const WebpEncodingMethod effort = WebpEncodingMethod.Default; const int quality = 8 * (int)effort; - using Vp8LEncoder lossLessEncoder = new Vp8LEncoder(memoryAllocator, configuration, width, height, quality, - skipMetadata, effort, WebpTransparentColorMode.Preserve, false, 0); + using Vp8LEncoder lossLessEncoder = new( + memoryAllocator, + configuration, + width, + height, + quality, + skipMetadata, + effort, + WebpTransparentColorMode.Preserve, + false, + 0); // The transparency information will be stored in the green channel of the ARGB quadruplet. // The green channel is allowed extra transformation steps in the specification -- unlike the other channels, diff --git a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs index 4ac516f055..354bcdbb44 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs @@ -76,7 +76,11 @@ internal sealed class WebpLossyDecoder Vp8Proba proba = new Vp8Proba(); Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba); - using (Vp8Decoder decoder = new Vp8Decoder(info.Vp8FrameHeader, pictureHeader, vp8SegmentHeader, proba, + using (Vp8Decoder decoder = new Vp8Decoder( + info.Vp8FrameHeader, + pictureHeader, + vp8SegmentHeader, + proba, this.memoryAllocator)) { Vp8Io io = InitializeVp8Io(decoder, pictureHeader); @@ -102,8 +106,13 @@ internal sealed class WebpLossyDecoder if (info.Features?.Alpha == true) { - using (AlphaDecoder alphaDecoder = new AlphaDecoder(width, height, alphaData, - info.Features.AlphaChunkHeader, this.memoryAllocator, this.configuration)) + using (AlphaDecoder alphaDecoder = new AlphaDecoder( + width, + height, + alphaData, + info.Features.AlphaChunkHeader, + this.memoryAllocator, + this.configuration)) { alphaDecoder.Decode(); DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index bb54d99a04..bc875c8890 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -91,8 +91,11 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable { if (this.webImageInfo.Features is { Animation: true }) { - using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder(this.memoryAllocator, - this.configuration, this.maxFrames, this.backgroundColorHandling); + using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder( + this.memoryAllocator, + this.configuration, + this.maxFrames, + this.backgroundColorHandling); return animationDecoder.Decode(stream, this.webImageInfo.Features, this.webImageInfo.Width, this.webImageInfo.Height, fileSize); } @@ -100,14 +103,18 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.webImageInfo.IsLossless) { - WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder(this.webImageInfo.Vp8LBitReader, - this.memoryAllocator, this.configuration); + WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder( + this.webImageInfo.Vp8LBitReader, + this.memoryAllocator, + this.configuration); losslessDecoder.Decode(pixels, image.Width, image.Height); } else { - WebpLossyDecoder lossyDecoder = new WebpLossyDecoder(this.webImageInfo.Vp8BitReader, - this.memoryAllocator, this.configuration); + WebpLossyDecoder lossyDecoder = new WebpLossyDecoder( + this.webImageInfo.Vp8BitReader, + this.memoryAllocator, + this.configuration); lossyDecoder.Decode(pixels, image.Width, image.Height, this.webImageInfo, this.alphaData); } diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index dcff53f3af..d945cc3990 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -129,9 +129,17 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals if (lossless) { - using Vp8LEncoder encoder = new Vp8LEncoder(this.memoryAllocator, this.configuration, image.Width, - image.Height, this.quality, this.skipMetadata, this.method, this.transparentColorMode, - this.nearLossless, this.nearLosslessQuality); + using Vp8LEncoder encoder = new Vp8LEncoder( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.transparentColorMode, + this.nearLossless, + this.nearLosslessQuality); bool hasAnimation = image.Frames.Count > 1; encoder.EncodeHeader(image, stream, hasAnimation); @@ -139,9 +147,17 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals { foreach (ImageFrame imageFrame in image.Frames) { - using Vp8LEncoder enc = new Vp8LEncoder(this.memoryAllocator, this.configuration, image.Width, - image.Height, this.quality, this.skipMetadata, this.method, this.transparentColorMode, - this.nearLossless, this.nearLosslessQuality); + using Vp8LEncoder enc = new Vp8LEncoder( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.transparentColorMode, + this.nearLossless, + this.nearLosslessQuality); enc.Encode(imageFrame, stream, true); } @@ -155,18 +171,36 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals } else { - using Vp8Encoder encoder = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, - image.Height, this.quality, this.skipMetadata, this.method, this.entropyPasses, this.filterStrength, - this.spatialNoiseShaping, this.alphaCompression); + using Vp8Encoder encoder = new Vp8Encoder( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.entropyPasses, + this.filterStrength, + this.spatialNoiseShaping, + this.alphaCompression); if (image.Frames.Count > 1) { encoder.EncodeHeader(image, stream, false, true); foreach (ImageFrame imageFrame in image.Frames) { - using Vp8Encoder enc = new Vp8Encoder(this.memoryAllocator, this.configuration, image.Width, - image.Height, this.quality, this.skipMetadata, this.method, this.entropyPasses, - this.filterStrength, this.spatialNoiseShaping, this.alphaCompression); + using Vp8Encoder enc = new Vp8Encoder( + this.memoryAllocator, + this.configuration, + image.Width, + image.Height, + this.quality, + this.skipMetadata, + this.method, + this.entropyPasses, + this.filterStrength, + this.spatialNoiseShaping, + this.alphaCompression); enc.EncodeAnimation(imageFrame, stream); } From b89bc54aa20b7868010d34734bd1a6ea88be92a2 Mon Sep 17 00:00:00 2001 From: Poker Date: Tue, 31 Oct 2023 18:27:35 +0800 Subject: [PATCH 019/219] Add new member to WebpFrameMetadata --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 8 +++-- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 30 +++++++++++-------- .../Formats/Webp/Lossy/Vp8Encoder.cs | 26 +++++++++------- .../Formats/Webp/WebpAnimationDecoder.cs | 29 +++++++++--------- ...lendingMethod.cs => WebpBlendingMethod.cs} | 2 +- .../Formats/Webp/WebpDecoderCore.cs | 16 +++++----- ...isposalMethod.cs => WebpDisposalMethod.cs} | 2 +- src/ImageSharp/Formats/Webp/WebpEncoder.cs | 4 +-- .../Formats/Webp/WebpEncoderCore.cs | 8 ++--- ...AnimationFrameData.cs => WebpFrameData.cs} | 14 ++++----- .../Formats/Webp/WebpFrameMetadata.cs | 19 ++++++++++-- src/ImageSharp/Formats/Webp/WebpMetadata.cs | 9 ++++++ .../Formats/WebP/WebpDecoderTests.cs | 4 +-- 13 files changed, 102 insertions(+), 69 deletions(-) rename src/ImageSharp/Formats/Webp/{AnimationBlendingMethod.cs => WebpBlendingMethod.cs} (95%) rename src/ImageSharp/Formats/Webp/{AnimationDisposalMethod.cs => WebpDisposalMethod.cs} (94%) rename src/ImageSharp/Formats/Webp/{AnimationFrameData.cs => WebpFrameData.cs} (83%) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 89db7ed645..c1860c9c59 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -231,14 +231,14 @@ internal abstract class BitWriterBase /// The background color is also used when the Disposal method is 1. /// /// The number of times to loop the animation. If it is 0, this means infinitely. - public static void WriteAnimationParameter(Stream stream, uint background, ushort loopCount) + public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount) { Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.AnimationParameter); stream.Write(buf); BinaryPrimitives.WriteUInt32LittleEndian(buf, sizeof(uint) + sizeof(ushort)); stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, background); + BinaryPrimitives.WriteUInt32LittleEndian(buf, background.ToRgba32().Rgba); stream.Write(buf); BinaryPrimitives.WriteUInt16LittleEndian(buf[..2], loopCount); stream.Write(buf[..2]); @@ -249,7 +249,7 @@ internal abstract class BitWriterBase /// /// The stream to write to. /// Animation frame data. - public static long WriteAnimationFrame(Stream stream, AnimationFrameData animation) + public static long WriteAnimationFrame(Stream stream, WebpFrameData animation) { Span buf = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation); @@ -262,6 +262,8 @@ internal abstract class BitWriterBase WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Width - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Height - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration); + + // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod); stream.WriteByte(flag); return position; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 3da27229ab..9156d5bdf8 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -235,7 +235,7 @@ internal class Vp8LEncoder : IDisposable /// public Vp8LHashChain HashChain { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAnimation, uint background = 0, uint loopCount = 0) + public void EncodeHeader(Image image, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -257,7 +257,8 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount); + WebpMetadata webpMetadata = metadata.GetWebpMetadata(); + BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount); } } @@ -304,11 +305,14 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData + WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData { Width = (uint)frame.Width, Height = (uint)frame.Height, - Duration = frame.Metadata.GetWebpMetadata().FrameDuration + Duration = frameMetadata.FrameDelay, + BlendingMethod = frameMetadata.BlendMethod, + DisposalMethod = frameMetadata.DisposalMethod }); } @@ -547,7 +551,7 @@ internal class Vp8LEncoder : IDisposable EntropyIx entropyIdx = this.AnalyzeEntropy(bgra, width, height, usePalette, this.PaletteSize, this.TransformBits, out redAndBlueAlwaysZero); bool doNotCache = false; - List crunchConfigs = new List(); + List crunchConfigs = new(); if (this.method == WebpEncodingMethod.BestQuality && this.quality == 100) { @@ -641,8 +645,8 @@ internal class Vp8LEncoder : IDisposable Vp8LBackwardRefs refsTmp = this.Refs[refsBest.Equals(this.Refs[0]) ? 1 : 0]; this.bitWriter.Reset(bwInit); - Vp8LHistogram tmpHisto = new Vp8LHistogram(cacheBits); - List histogramImage = new List(histogramImageXySize); + Vp8LHistogram tmpHisto = new(cacheBits); + List histogramImage = new(histogramImageXySize); for (int i = 0; i < histogramImageXySize; i++) { histogramImage.Add(new Vp8LHistogram(cacheBits)); @@ -839,7 +843,7 @@ internal class Vp8LEncoder : IDisposable refsTmp1, refsTmp2); - List histogramImage = new List + List histogramImage = new() { new Vp8LHistogram(cacheBits) }; @@ -941,7 +945,7 @@ internal class Vp8LEncoder : IDisposable int i; byte[] codeLengthBitDepth = new byte[WebpConstants.CodeLengthCodes]; short[] codeLengthBitDepthSymbols = new short[WebpConstants.CodeLengthCodes]; - HuffmanTreeCode huffmanCode = new HuffmanTreeCode + HuffmanTreeCode huffmanCode = new() { NumSymbols = WebpConstants.CodeLengthCodes, CodeLengths = codeLengthBitDepth, @@ -1192,7 +1196,7 @@ internal class Vp8LEncoder : IDisposable histo[(int)HistoIx.HistoBluePred * 256]++; histo[(int)HistoIx.HistoAlphaPred * 256]++; - Vp8LBitEntropy bitEntropy = new Vp8LBitEntropy(); + Vp8LBitEntropy bitEntropy = new(); for (int j = 0; j < (int)HistoIx.HistoTotal; j++) { bitEntropy.Init(); @@ -1318,7 +1322,7 @@ internal class Vp8LEncoder : IDisposable /// The number of palette entries. private static int GetColorPalette(ReadOnlySpan bgra, int width, int height, Span palette) { - HashSet colors = new HashSet(); + HashSet colors = new(); for (int y = 0; y < height; y++) { ReadOnlySpan bgraRow = bgra.Slice(y * width, width); @@ -1870,9 +1874,9 @@ internal class Vp8LEncoder : IDisposable /// public void ClearRefs() { - for (int i = 0; i < this.Refs.Length; i++) + foreach (Vp8LBackwardRefs t in this.Refs) { - this.Refs[i].Refs.Clear(); + t.Refs.Clear(); } } diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index e62eb6cfc3..3a6e9a2ccd 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -309,7 +309,7 @@ internal class Vp8Encoder : IDisposable /// private int MbHeaderLimit { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation, uint background = 0, uint loopCount = 0) + public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -331,7 +331,8 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - BitWriterBase.WriteAnimationParameter(stream, background, (ushort)loopCount); + WebpMetadata webpMetadata = metadata.GetWebpMetadata(); + BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount); } } @@ -395,7 +396,7 @@ internal class Vp8Encoder : IDisposable int yStride = width; int uvStride = (yStride + 1) >> 1; - Vp8EncIterator it = new Vp8EncIterator(this); + Vp8EncIterator it = new(this); Span alphas = stackalloc 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; @@ -416,8 +417,8 @@ internal class Vp8Encoder : IDisposable this.StatLoop(width, height, yStride, uvStride); it.Init(); Vp8EncIterator.InitFilter(); - Vp8ModeScore info = new Vp8ModeScore(); - Vp8Residual residual = new Vp8Residual(); + Vp8ModeScore info = new(); + Vp8Residual residual = new(); do { bool dontUseSkip = !this.Proba.UseSkipProba; @@ -474,11 +475,14 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new AnimationFrameData + WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData { Width = (uint)frame.Width, Height = (uint)frame.Height, - Duration = frame.Metadata.GetWebpMetadata().FrameDuration + Duration = frameMetadata.FrameDelay, + BlendingMethod = frameMetadata.BlendMethod, + DisposalMethod = frameMetadata.DisposalMethod }); } @@ -529,7 +533,7 @@ internal class Vp8Encoder : IDisposable Vp8RdLevel rdOpt = this.method >= WebpEncodingMethod.Level3 || doSearch ? Vp8RdLevel.RdOptBasic : Vp8RdLevel.RdOptNone; int nbMbs = this.Mbw * this.Mbh; - PassStats stats = new PassStats(targetSize, targetPsnr, QMin, QMax, this.quality); + PassStats stats = new(targetSize, targetPsnr, QMin, QMax, this.quality); this.Proba.ResetTokenStats(); // Fast mode: quick analysis pass over few mbs. Better than nothing. @@ -597,7 +601,7 @@ internal class Vp8Encoder : IDisposable Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - Vp8EncIterator it = new Vp8EncIterator(this); + Vp8EncIterator it = new(this); long size = 0; long sizeP0 = 0; long distortion = 0; @@ -605,7 +609,7 @@ internal class Vp8Encoder : IDisposable it.Init(); this.SetLoopParams(stats.Q); - Vp8ModeScore info = new Vp8ModeScore(); + Vp8ModeScore info = new(); do { info.Clear(); @@ -1167,7 +1171,7 @@ internal class Vp8Encoder : IDisposable private void RecordResiduals(Vp8EncIterator it, Vp8ModeScore rd) { int x, y, ch; - Vp8Residual residual = new Vp8Residual(); + Vp8Residual residual = new(); bool i16 = it.CurrentMacroBlockInfo.MacroBlockType == Vp8MacroBlockType.I16X16; it.NzToBytes(); diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 6922e37d6e..87657dfabb 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -138,7 +138,7 @@ internal class WebpAnimationDecoder : IDisposable private uint ReadFrame(BufferedReadStream stream, ref Image? image, ref ImageFrame? previousFrame, uint width, uint height, Color backgroundColor) where TPixel : unmanaged, IPixel { - AnimationFrameData frameData = AnimationFrameData.Parse(stream); + WebpFrameData frameData = WebpFrameData.Parse(stream); long streamStartPosition = stream.Position; Span buffer = stackalloc byte[4]; @@ -153,7 +153,7 @@ internal class WebpAnimationDecoder : IDisposable } WebpImageInfo? webpInfo = null; - WebpFeatures features = new WebpFeatures(); + WebpFeatures features = new(); switch (chunkType) { case WebpChunkType.Vp8: @@ -180,7 +180,7 @@ internal class WebpAnimationDecoder : IDisposable { image = new Image(this.configuration, (int)width, (int)height, backgroundColor.ToPixel(), this.metadata); - SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData.Duration); + SetFrameMetadata(image.Frames.RootFrame.Metadata, frameData); imageFrame = image.Frames.RootFrame; } @@ -188,7 +188,7 @@ internal class WebpAnimationDecoder : IDisposable { currentFrame = image!.Frames.AddFrame(previousFrame); // This clones the frame and adds it the collection. - SetFrameMetadata(currentFrame.Metadata, frameData.Duration); + SetFrameMetadata(currentFrame.Metadata, frameData); imageFrame = currentFrame; } @@ -199,7 +199,7 @@ internal class WebpAnimationDecoder : IDisposable int frameHeight = (int)frameData.Height; Rectangle regionRectangle = Rectangle.FromLTRB(frameX, frameY, frameX + frameWidth, frameY + frameHeight); - if (frameData.DisposalMethod is AnimationDisposalMethod.Dispose) + if (frameData.DisposalMethod is WebpDisposalMethod.Dispose) { this.RestoreToBackground(imageFrame, backgroundColor); } @@ -207,7 +207,7 @@ internal class WebpAnimationDecoder : IDisposable using Buffer2D decodedImage = this.DecodeImageData(frameData, webpInfo); DrawDecodedImageOnCanvas(decodedImage, imageFrame, frameX, frameY, frameWidth, frameHeight); - if (previousFrame != null && frameData.BlendingMethod is AnimationBlendingMethod.AlphaBlending) + if (previousFrame != null && frameData.BlendingMethod is WebpBlendingMethod.AlphaBlending) { this.AlphaBlend(previousFrame, imageFrame, frameX, frameY, frameWidth, frameHeight); } @@ -222,12 +222,13 @@ internal class WebpAnimationDecoder : IDisposable /// Sets the frames metadata. /// /// The metadata. - /// The frame duration. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void SetFrameMetadata(ImageFrameMetadata meta, uint duration) + /// The frame data. + private static void SetFrameMetadata(ImageFrameMetadata meta, WebpFrameData frameData) { WebpFrameMetadata frameMetadata = meta.GetWebpMetadata(); - frameMetadata.FrameDuration = duration; + frameMetadata.FrameDelay = frameData.Duration; + frameMetadata.BlendMethod = frameData.BlendingMethod; + frameMetadata.DisposalMethod = frameData.DisposalMethod; } /// @@ -256,10 +257,10 @@ internal class WebpAnimationDecoder : IDisposable /// The frame data. /// The webp information. /// A decoded image. - private Buffer2D DecodeImageData(AnimationFrameData frameData, WebpImageInfo webpInfo) + private Buffer2D DecodeImageData(WebpFrameData frameData, WebpImageInfo webpInfo) where TPixel : unmanaged, IPixel { - Image decodedImage = new Image((int)frameData.Width, (int)frameData.Height); + Image decodedImage = new((int)frameData.Width, (int)frameData.Height); try { @@ -267,13 +268,13 @@ internal class WebpAnimationDecoder : IDisposable if (webpInfo.IsLossless) { WebpLosslessDecoder losslessDecoder = - new WebpLosslessDecoder(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); + new(webpInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); losslessDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height); } else { WebpLossyDecoder lossyDecoder = - new WebpLossyDecoder(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration); + new(webpInfo.Vp8BitReader, this.memoryAllocator, this.configuration); lossyDecoder.Decode(pixelBufferDecoded, (int)webpInfo.Width, (int)webpInfo.Height, webpInfo, this.alphaData); } diff --git a/src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs similarity index 95% rename from src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs rename to src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs index 99b2462cea..cbd0e9a8cc 100644 --- a/src/ImageSharp/Formats/Webp/AnimationBlendingMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// /// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// -internal enum AnimationBlendingMethod +public enum WebpBlendingMethod { /// /// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending. diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index bc875c8890..de188b137b 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -73,7 +73,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable public DecoderOptions Options { get; } /// - public Size Dimensions => new Size((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height); + public Size Dimensions => new((int)this.webImageInfo!.Width, (int)this.webImageInfo.Height); /// public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) @@ -82,7 +82,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Image? image = null; try { - ImageMetadata metadata = new ImageMetadata(); + ImageMetadata metadata = new(); Span buffer = stackalloc byte[4]; uint fileSize = ReadImageHeader(stream, buffer); @@ -91,7 +91,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable { if (this.webImageInfo.Features is { Animation: true }) { - using WebpAnimationDecoder animationDecoder = new WebpAnimationDecoder( + using WebpAnimationDecoder animationDecoder = new( this.memoryAllocator, this.configuration, this.maxFrames, @@ -103,7 +103,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.webImageInfo.IsLossless) { - WebpLosslessDecoder losslessDecoder = new WebpLosslessDecoder( + WebpLosslessDecoder losslessDecoder = new( this.webImageInfo.Vp8LBitReader, this.memoryAllocator, this.configuration); @@ -111,7 +111,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable } else { - WebpLossyDecoder lossyDecoder = new WebpLossyDecoder( + WebpLossyDecoder lossyDecoder = new( this.webImageInfo.Vp8BitReader, this.memoryAllocator, this.configuration); @@ -139,7 +139,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable { ReadImageHeader(stream, stackalloc byte[4]); - ImageMetadata metadata = new ImageMetadata(); + ImageMetadata metadata = new(); using (this.webImageInfo = this.ReadVp8Info(stream, metadata, true)) { return new ImageInfo( @@ -185,7 +185,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable Span buffer = stackalloc byte[4]; WebpChunkType chunkType = WebpChunkParsingUtils.ReadChunkType(stream, buffer); - WebpFeatures features = new WebpFeatures(); + WebpFeatures features = new(); switch (chunkType) { case WebpChunkType.Vp8: @@ -392,7 +392,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable WebpThrowHelper.ThrowInvalidImageContentException("Not enough data to read the iccp chunk"); } - IccProfile profile = new IccProfile(iccpData); + IccProfile profile = new(iccpData); if (profile.CheckIsValid()) { metadata.IccProfile = profile; diff --git a/src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs similarity index 94% rename from src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs rename to src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs index 23bc37c283..d409973a99 100644 --- a/src/ImageSharp/Formats/Webp/AnimationDisposalMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// /// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. /// -internal enum AnimationDisposalMethod +public enum WebpDisposalMethod { /// /// Do not dispose. Leave the canvas as is. diff --git a/src/ImageSharp/Formats/Webp/WebpEncoder.cs b/src/ImageSharp/Formats/Webp/WebpEncoder.cs index 13c9798dbb..bc93df3a5b 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; - namespace SixLabors.ImageSharp.Formats.Webp; /// @@ -82,7 +80,7 @@ public sealed class WebpEncoder : ImageEncoder /// protected override void Encode(Image image, Stream stream, CancellationToken cancellationToken) { - WebpEncoderCore encoder = new WebpEncoderCore(this, image.Configuration); + WebpEncoderCore encoder = new(this, image.Configuration); encoder.Encode(image, stream, cancellationToken); } } diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index d945cc3990..47712071bf 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -129,7 +129,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals if (lossless) { - using Vp8LEncoder encoder = new Vp8LEncoder( + using Vp8LEncoder encoder = new( this.memoryAllocator, this.configuration, image.Width, @@ -147,7 +147,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals { foreach (ImageFrame imageFrame in image.Frames) { - using Vp8LEncoder enc = new Vp8LEncoder( + using Vp8LEncoder enc = new( this.memoryAllocator, this.configuration, image.Width, @@ -171,7 +171,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals } else { - using Vp8Encoder encoder = new Vp8Encoder( + using Vp8Encoder encoder = new( this.memoryAllocator, this.configuration, image.Width, @@ -189,7 +189,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals foreach (ImageFrame imageFrame in image.Frames) { - using Vp8Encoder enc = new Vp8Encoder( + using Vp8Encoder enc = new( this.memoryAllocator, this.configuration, image.Width, diff --git a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs b/src/ImageSharp/Formats/Webp/WebpFrameData.cs similarity index 83% rename from src/ImageSharp/Formats/Webp/AnimationFrameData.cs rename to src/ImageSharp/Formats/Webp/WebpFrameData.cs index 27a1815fe3..e2bcfd7c36 100644 --- a/src/ImageSharp/Formats/Webp/AnimationFrameData.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameData.cs @@ -5,7 +5,7 @@ using SixLabors.ImageSharp.IO; namespace SixLabors.ImageSharp.Formats.Webp; -internal struct AnimationFrameData +internal struct WebpFrameData { /// /// The animation chunk size. @@ -46,23 +46,23 @@ internal struct AnimationFrameData /// /// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// - public AnimationBlendingMethod BlendingMethod; + public WebpBlendingMethod BlendingMethod; /// /// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. /// - public AnimationDisposalMethod DisposalMethod; + public WebpDisposalMethod DisposalMethod; /// /// Reads the animation frame header. /// /// The stream to read from. /// Animation frame data. - public static AnimationFrameData Parse(BufferedReadStream stream) + public static WebpFrameData Parse(BufferedReadStream stream) { Span buffer = stackalloc byte[4]; - AnimationFrameData data = new AnimationFrameData + WebpFrameData data = new() { DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer), @@ -83,8 +83,8 @@ internal struct AnimationFrameData }; byte flags = (byte)stream.ReadByte(); - data.DisposalMethod = (flags & 1) == 1 ? AnimationDisposalMethod.Dispose : AnimationDisposalMethod.DoNotDispose; - data.BlendingMethod = (flags & (1 << 1)) != 0 ? AnimationBlendingMethod.DoNotBlend : AnimationBlendingMethod.AlphaBlending; + data.DisposalMethod = (flags & 1) == 1 ? WebpDisposalMethod.Dispose : WebpDisposalMethod.DoNotDispose; + data.BlendingMethod = (flags & (1 << 1)) != 0 ? WebpBlendingMethod.DoNotBlend : WebpBlendingMethod.AlphaBlending; return data; } diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index bce1b09d6f..ef21d8b6fe 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -19,13 +19,28 @@ public class WebpFrameMetadata : IDeepCloneable /// Initializes a new instance of the class. /// /// The metadata to create an instance from. - private WebpFrameMetadata(WebpFrameMetadata other) => this.FrameDuration = other.FrameDuration; + private WebpFrameMetadata(WebpFrameMetadata other) + { + this.FrameDelay = other.FrameDelay; + this.DisposalMethod = other.DisposalMethod; + this.BlendMethod = other.BlendMethod; + } + + /// + /// Gets or sets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. + /// + public WebpBlendingMethod BlendMethod { get; set; } + + /// + /// Gets or sets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. + /// + public WebpDisposalMethod DisposalMethod { get; set; } /// /// Gets or sets the frame duration. The time to wait before displaying the next frame, /// in 1 millisecond units. Note the interpretation of frame duration of 0 (and often smaller and equal to 10) is implementation defined. /// - public uint FrameDuration { get; set; } + public uint FrameDelay { get; set; } /// public IDeepCloneable DeepClone() => new WebpFrameMetadata(this); diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs index 5d1051c751..a6bb0a7b80 100644 --- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs @@ -23,6 +23,7 @@ public class WebpMetadata : IDeepCloneable { this.FileFormat = other.FileFormat; this.AnimationLoopCount = other.AnimationLoopCount; + this.AnimationBackground = other.AnimationBackground; } /// @@ -35,6 +36,14 @@ public class WebpMetadata : IDeepCloneable /// public ushort AnimationLoopCount { get; set; } = 1; + /// + /// Gets or sets the default background color of the canvas in [Blue, Green, Red, Alpha] byte order. + /// This color MAY be used to fill the unused space on the canvas around the frames, + /// as well as the transparent pixels of the first frame. + /// The background color is also used when the Disposal method is 1. + /// + public Color AnimationBackground { get; set; } + /// public IDeepCloneable DeepClone() => new WebpMetadata(this); } diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index c0fc00b82d..c3a777c153 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -308,7 +308,7 @@ public class WebpDecoderTests image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact); Assert.Equal(0, webpMetaData.AnimationLoopCount); - Assert.Equal(150U, frameMetaData.FrameDuration); + Assert.Equal(150U, frameMetaData.FrameDelay); Assert.Equal(12, image.Frames.Count); } @@ -325,7 +325,7 @@ public class WebpDecoderTests image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Tolerant(0.04f)); Assert.Equal(0, webpMetaData.AnimationLoopCount); - Assert.Equal(150U, frameMetaData.FrameDuration); + Assert.Equal(150U, frameMetaData.FrameDelay); Assert.Equal(12, image.Frames.Count); } From b4e1b7f4e105360698fa155257c8d72c59bf52e2 Mon Sep 17 00:00:00 2001 From: Poker Date: Wed, 1 Nov 2023 22:46:20 +0800 Subject: [PATCH 020/219] fix --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 1 - .../Formats/Webp/Lossless/Vp8LEncoder.cs | 4 + .../Webp/Lossless/WebpLosslessDecoder.cs | 115 +++++----- .../Formats/Webp/Lossy/Vp8Encoder.cs | 4 + .../Formats/Webp/Lossy/WebpLossyDecoder.cs | 198 +++++++++--------- .../Formats/Webp/WebpAnimationDecoder.cs | 53 ++--- src/ImageSharp/Formats/Webp/WebpFrameData.cs | 2 + 7 files changed, 188 insertions(+), 189 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index c1860c9c59..cbf96a91af 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -263,7 +263,6 @@ internal abstract class BitWriterBase WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Height - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration); - // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod); stream.WriteByte(flag); return position; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 9156d5bdf8..42aa667ac5 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -306,8 +306,12 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + + // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData { + X = 0, + Y = 0, Width = (uint)frame.Width, Height = (uint)frame.Height, Duration = frameMetadata.FrameDelay, diff --git a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs index 54dd1d6ed1..e4c2a7ddf6 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/WebpLosslessDecoder.cs @@ -95,12 +95,10 @@ internal sealed class WebpLosslessDecoder public void Decode(Buffer2D pixels, int width, int height) where TPixel : unmanaged, IPixel { - using (Vp8LDecoder decoder = new Vp8LDecoder(width, height, this.memoryAllocator)) - { - this.DecodeImageStream(decoder, width, height, true); - this.DecodeImageData(decoder, decoder.Pixels.Memory.Span); - this.DecodePixelValues(decoder, pixels, width, height); - } + using Vp8LDecoder decoder = new(width, height, this.memoryAllocator); + this.DecodeImageStream(decoder, width, height, true); + this.DecodeImageData(decoder, decoder.Pixels.Memory.Span); + this.DecodePixelValues(decoder, pixels, width, height); } public IMemoryOwner DecodeImageStream(Vp8LDecoder decoder, int xSize, int ySize, bool isLevel0) @@ -616,15 +614,12 @@ internal sealed class WebpLosslessDecoder private void ReadTransformation(int xSize, int ySize, Vp8LDecoder decoder) { Vp8LTransformType transformType = (Vp8LTransformType)this.bitReader.ReadValue(2); - Vp8LTransform transform = new Vp8LTransform(transformType, xSize, ySize); + Vp8LTransform transform = new(transformType, xSize, ySize); // Each transform is allowed to be used only once. - foreach (Vp8LTransform decoderTransform in decoder.Transforms) + if (decoder.Transforms.Any(decoderTransform => decoderTransform.TransformType == transform.TransformType)) { - if (decoderTransform.TransformType == transform.TransformType) - { - WebpThrowHelper.ThrowImageFormatException("Each transform can only be present once"); - } + WebpThrowHelper.ThrowImageFormatException("Each transform can only be present once"); } switch (transformType) @@ -744,61 +739,69 @@ internal sealed class WebpLosslessDecoder this.bitReader.FillBitWindow(); int code = (int)this.ReadSymbol(htreeGroup[0].HTrees[HuffIndex.Green]); - if (code < WebpConstants.NumLiteralCodes) + switch (code) { - // Literal - data[pos] = (byte)code; - ++pos; - ++col; - - if (col >= width) + case < WebpConstants.NumLiteralCodes: { - col = 0; - ++row; - if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0) + // Literal + data[pos] = (byte)code; + ++pos; + ++col; + + if (col >= width) { - dec.ExtractPalettedAlphaRows(row); + col = 0; + ++row; + if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0) + { + dec.ExtractPalettedAlphaRows(row); + } } - } - } - else if (code < lenCodeLimit) - { - // Backward reference - int lengthSym = code - WebpConstants.NumLiteralCodes; - int length = this.GetCopyLength(lengthSym); - int distSymbol = (int)this.ReadSymbol(htreeGroup[0].HTrees[HuffIndex.Dist]); - this.bitReader.FillBitWindow(); - int distCode = this.GetCopyDistance(distSymbol); - int dist = PlaneCodeToDistance(width, distCode); - if (pos >= dist && end - pos >= length) - { - CopyBlock8B(data, pos, dist, length); - } - else - { - WebpThrowHelper.ThrowImageFormatException("error while decoding alpha data"); + + break; } - pos += length; - col += length; - while (col >= width) + case < lenCodeLimit: { - col -= width; - ++row; - if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0) + // Backward reference + int lengthSym = code - WebpConstants.NumLiteralCodes; + int length = this.GetCopyLength(lengthSym); + int distSymbol = (int)this.ReadSymbol(htreeGroup[0].HTrees[HuffIndex.Dist]); + this.bitReader.FillBitWindow(); + int distCode = this.GetCopyDistance(distSymbol); + int dist = PlaneCodeToDistance(width, distCode); + if (pos >= dist && end - pos >= length) { - dec.ExtractPalettedAlphaRows(row); + CopyBlock8B(data, pos, dist, length); + } + else + { + WebpThrowHelper.ThrowImageFormatException("error while decoding alpha data"); } - } - if (pos < last && (col & mask) > 0) - { - htreeGroup = GetHTreeGroupForPos(hdr, col, row); + pos += length; + col += length; + while (col >= width) + { + col -= width; + ++row; + if (row <= lastRow && row % WebpConstants.NumArgbCacheRows == 0) + { + dec.ExtractPalettedAlphaRows(row); + } + } + + if (pos < last && (col & mask) > 0) + { + htreeGroup = GetHTreeGroupForPos(hdr, col, row); + } + + break; } - } - else - { - WebpThrowHelper.ThrowImageFormatException("bitstream error while parsing alpha data"); + + default: + WebpThrowHelper.ThrowImageFormatException("bitstream error while parsing alpha data"); + break; } this.bitReader.Eos = this.bitReader.IsEndOfStream(); diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 3a6e9a2ccd..3b73023062 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -476,8 +476,12 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + + // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData { + X = 0, + Y = 0, Width = (uint)frame.Width, Height = (uint)frame.Height, Duration = frameMetadata.FrameDelay, diff --git a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs index 354bcdbb44..3eb03b1724 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs @@ -62,7 +62,7 @@ internal sealed class WebpLossyDecoder // Paragraph 9.2: color space and clamp type follow. sbyte colorSpace = (sbyte)this.bitReader.ReadValue(1); sbyte clampType = (sbyte)this.bitReader.ReadValue(1); - Vp8PictureHeader pictureHeader = new Vp8PictureHeader + Vp8PictureHeader pictureHeader = new() { Width = (uint)width, Height = (uint)height, @@ -73,55 +73,51 @@ internal sealed class WebpLossyDecoder }; // Paragraph 9.3: Parse the segment header. - Vp8Proba proba = new Vp8Proba(); + Vp8Proba proba = new(); Vp8SegmentHeader vp8SegmentHeader = this.ParseSegmentHeader(proba); - using (Vp8Decoder decoder = new Vp8Decoder( - info.Vp8FrameHeader, - pictureHeader, - vp8SegmentHeader, - proba, - this.memoryAllocator)) - { - Vp8Io io = InitializeVp8Io(decoder, pictureHeader); + using Vp8Decoder decoder = new( + info.Vp8FrameHeader, + pictureHeader, + vp8SegmentHeader, + proba, + this.memoryAllocator); + Vp8Io io = InitializeVp8Io(decoder, pictureHeader); - // Paragraph 9.4: Parse the filter specs. - this.ParseFilterHeader(decoder); - decoder.PrecomputeFilterStrengths(); + // Paragraph 9.4: Parse the filter specs. + this.ParseFilterHeader(decoder); + decoder.PrecomputeFilterStrengths(); - // Paragraph 9.5: Parse partitions. - this.ParsePartitions(decoder); + // Paragraph 9.5: Parse partitions. + this.ParsePartitions(decoder); - // Paragraph 9.6: Dequantization Indices. - this.ParseDequantizationIndices(decoder); + // Paragraph 9.6: Dequantization Indices. + this.ParseDequantizationIndices(decoder); - // Ignore the value of update probabilities. - this.bitReader.ReadBool(); + // Ignore the value of update probabilities. + this.bitReader.ReadBool(); - // Paragraph 13.4: Parse probabilities. - this.ParseProbabilities(decoder); + // Paragraph 13.4: Parse probabilities. + this.ParseProbabilities(decoder); - // Decode image data. - this.ParseFrame(decoder, io); + // Decode image data. + this.ParseFrame(decoder, io); - if (info.Features?.Alpha == true) - { - using (AlphaDecoder alphaDecoder = new AlphaDecoder( - width, - height, - alphaData, - info.Features.AlphaChunkHeader, - this.memoryAllocator, - this.configuration)) - { - alphaDecoder.Decode(); - DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); - } - } - else - { - this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels); - } + if (info.Features?.Alpha == true) + { + using AlphaDecoder alphaDecoder = new( + width, + height, + alphaData, + info.Features.AlphaChunkHeader, + this.memoryAllocator, + this.configuration); + alphaDecoder.Decode(); + DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels, alphaDecoder.Alpha); + } + else + { + this.DecodePixelValues(width, height, decoder.Pixels.Memory.Span, pixels); } } @@ -199,8 +195,8 @@ internal sealed class WebpLossyDecoder { // Hardcoded tree parsing. block.Segment = this.bitReader.GetBit((int)dec.Probabilities.Segments[0]) == 0 - ? (byte)this.bitReader.GetBit((int)dec.Probabilities.Segments[1]) - : (byte)(this.bitReader.GetBit((int)dec.Probabilities.Segments[2]) + 2); + ? (byte)this.bitReader.GetBit((int)dec.Probabilities.Segments[1]) + : (byte)(this.bitReader.GetBit((int)dec.Probabilities.Segments[2]) + 2); } else { @@ -595,57 +591,65 @@ internal sealed class WebpLossyDecoder return; } - if (dec.Filter == LoopFilter.Simple) + switch (dec.Filter) { - int offset = dec.CacheYOffset + (mbx * 16); - if (mbx > 0) + case LoopFilter.Simple: { - LossyUtils.SimpleHFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); - } + int offset = dec.CacheYOffset + (mbx * 16); + if (mbx > 0) + { + LossyUtils.SimpleHFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); + } - if (filterInfo.UseInnerFiltering) - { - LossyUtils.SimpleHFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); - } + if (filterInfo.UseInnerFiltering) + { + LossyUtils.SimpleHFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); + } - if (mby > 0) - { - LossyUtils.SimpleVFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); - } + if (mby > 0) + { + LossyUtils.SimpleVFilter16(dec.CacheY.Memory.Span, offset, yBps, limit + 4); + } - if (filterInfo.UseInnerFiltering) - { - LossyUtils.SimpleVFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); - } - } - else if (dec.Filter == LoopFilter.Complex) - { - int uvBps = dec.CacheUvStride; - int yOffset = dec.CacheYOffset + (mbx * 16); - int uvOffset = dec.CacheUvOffset + (mbx * 8); - int hevThresh = filterInfo.HighEdgeVarianceThreshold; - if (mbx > 0) - { - LossyUtils.HFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); - LossyUtils.HFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); - } + if (filterInfo.UseInnerFiltering) + { + LossyUtils.SimpleVFilter16i(dec.CacheY.Memory.Span, offset, yBps, limit); + } - if (filterInfo.UseInnerFiltering) - { - LossyUtils.HFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); - LossyUtils.HFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); + break; } - if (mby > 0) + case LoopFilter.Complex: { - LossyUtils.VFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); - LossyUtils.VFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); - } + int uvBps = dec.CacheUvStride; + int yOffset = dec.CacheYOffset + (mbx * 16); + int uvOffset = dec.CacheUvOffset + (mbx * 8); + int hevThresh = filterInfo.HighEdgeVarianceThreshold; + if (mbx > 0) + { + LossyUtils.HFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); + LossyUtils.HFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); + } - if (filterInfo.UseInnerFiltering) - { - LossyUtils.VFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); - LossyUtils.VFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); + if (filterInfo.UseInnerFiltering) + { + LossyUtils.HFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); + LossyUtils.HFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); + } + + if (mby > 0) + { + LossyUtils.VFilter16(dec.CacheY.Memory.Span, yOffset, yBps, limit + 4, iLevel, hevThresh); + LossyUtils.VFilter8(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit + 4, iLevel, hevThresh); + } + + if (filterInfo.UseInnerFiltering) + { + LossyUtils.VFilter16i(dec.CacheY.Memory.Span, yOffset, yBps, limit, iLevel, hevThresh); + LossyUtils.VFilter8i(dec.CacheU.Memory.Span, dec.CacheV.Memory.Span, uvOffset, uvBps, limit, iLevel, hevThresh); + } + + break; } } } @@ -1067,7 +1071,7 @@ internal sealed class WebpLossyDecoder private Vp8SegmentHeader ParseSegmentHeader(Vp8Proba proba) { - Vp8SegmentHeader vp8SegmentHeader = new Vp8SegmentHeader + Vp8SegmentHeader vp8SegmentHeader = new() { UseSegment = this.bitReader.ReadBool() }; @@ -1333,18 +1337,12 @@ internal sealed class WebpLossyDecoder private static uint NzCodeBits(uint nzCoeffs, int nz, int dcNz) { nzCoeffs <<= 2; - if (nz > 3) + nzCoeffs |= nz switch { - nzCoeffs |= 3; - } - else if (nz > 1) - { - nzCoeffs |= 2; - } - else - { - nzCoeffs |= (uint)dcNz; - } + > 3 => 3, + > 1 => 2, + _ => (uint)dcNz + }; return nzCoeffs; } @@ -1358,13 +1356,13 @@ internal sealed class WebpLossyDecoder if (mbx == 0) { return mby == 0 - ? 6 // B_DC_PRED_NOTOPLEFT - : 5; // B_DC_PRED_NOLEFT + ? 6 // B_DC_PRED_NOTOPLEFT + : 5; // B_DC_PRED_NOLEFT } return mby == 0 - ? 4 // B_DC_PRED_NOTOP - : 0; // B_DC_PRED + ? 4 // B_DC_PRED_NOTOP + : 0; // B_DC_PRED } return mode; diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 87657dfabb..fad6ca16cc 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; @@ -193,11 +192,7 @@ internal class WebpAnimationDecoder : IDisposable imageFrame = currentFrame; } - int frameX = (int)(frameData.X * 2); - int frameY = (int)(frameData.Y * 2); - int frameWidth = (int)frameData.Width; - int frameHeight = (int)frameData.Height; - Rectangle regionRectangle = Rectangle.FromLTRB(frameX, frameY, frameX + frameWidth, frameY + frameHeight); + Rectangle regionRectangle = frameData.Bounds; if (frameData.DisposalMethod is WebpDisposalMethod.Dispose) { @@ -205,11 +200,11 @@ internal class WebpAnimationDecoder : IDisposable } using Buffer2D decodedImage = this.DecodeImageData(frameData, webpInfo); - DrawDecodedImageOnCanvas(decodedImage, imageFrame, frameX, frameY, frameWidth, frameHeight); + DrawDecodedImageOnCanvas(decodedImage, imageFrame, regionRectangle); if (previousFrame != null && frameData.BlendingMethod is WebpBlendingMethod.AlphaBlending) { - this.AlphaBlend(previousFrame, imageFrame, frameX, frameY, frameWidth, frameHeight); + this.AlphaBlend(previousFrame, imageFrame, regionRectangle); } previousFrame = currentFrame ?? image.Frames.RootFrame; @@ -245,7 +240,7 @@ internal class WebpAnimationDecoder : IDisposable byte alphaChunkHeader = (byte)stream.ReadByte(); Span alphaData = this.alphaData.GetSpan(); - stream.Read(alphaData, 0, alphaDataSize); + _ = stream.Read(alphaData, 0, alphaDataSize); return alphaChunkHeader; } @@ -260,11 +255,11 @@ internal class WebpAnimationDecoder : IDisposable private Buffer2D DecodeImageData(WebpFrameData frameData, WebpImageInfo webpInfo) where TPixel : unmanaged, IPixel { - Image decodedImage = new((int)frameData.Width, (int)frameData.Height); + ImageFrame decodedFrame = new(Configuration.Default, (int)frameData.Width, (int)frameData.Height); try { - Buffer2D pixelBufferDecoded = decodedImage.GetRootFramePixelBuffer(); + Buffer2D pixelBufferDecoded = decodedFrame.PixelBuffer; if (webpInfo.IsLossless) { WebpLosslessDecoder losslessDecoder = @@ -282,7 +277,7 @@ internal class WebpAnimationDecoder : IDisposable } catch { - decodedImage?.Dispose(); + decodedFrame?.Dispose(); throw; } finally @@ -297,20 +292,17 @@ internal class WebpAnimationDecoder : IDisposable /// The type of the pixel. /// The decoded image. /// The image frame to draw into. - /// The frame x coordinate. - /// The frame y coordinate. - /// The width of the frame. - /// The height of the frame. - private static void DrawDecodedImageOnCanvas(Buffer2D decodedImage, ImageFrame imageFrame, int frameX, int frameY, int frameWidth, int frameHeight) + /// The area of the frame. + private static void DrawDecodedImageOnCanvas(Buffer2D decodedImage, ImageFrame imageFrame, Rectangle restoreArea) where TPixel : unmanaged, IPixel { - Buffer2D imageFramePixels = imageFrame.PixelBuffer; + Buffer2DRegion imageFramePixels = imageFrame.PixelBuffer.GetRegion(restoreArea); int decodedRowIdx = 0; - for (int y = frameY; y < frameY + frameHeight; y++) + for (int y = 0; y < restoreArea.Height; y++) { Span framePixelRow = imageFramePixels.DangerousGetRowSpan(y); - Span decodedPixelRow = decodedImage.DangerousGetRowSpan(decodedRowIdx++)[..frameWidth]; - decodedPixelRow.TryCopyTo(framePixelRow[frameX..]); + Span decodedPixelRow = decodedImage.DangerousGetRowSpan(decodedRowIdx++)[..restoreArea.Width]; + decodedPixelRow.TryCopyTo(framePixelRow); } } @@ -321,22 +313,19 @@ internal class WebpAnimationDecoder : IDisposable /// The pixel format. /// The source image. /// The destination image. - /// The frame x coordinate. - /// The frame y coordinate. - /// The width of the frame. - /// The height of the frame. - private void AlphaBlend(ImageFrame src, ImageFrame dst, int frameX, int frameY, int frameWidth, int frameHeight) + /// The area of the frame. + private void AlphaBlend(ImageFrame src, ImageFrame dst, Rectangle restoreArea) where TPixel : unmanaged, IPixel { - Buffer2D srcPixels = src.PixelBuffer; - Buffer2D dstPixels = dst.PixelBuffer; + Buffer2DRegion srcPixels = src.PixelBuffer.GetRegion(restoreArea); + Buffer2DRegion dstPixels = dst.PixelBuffer.GetRegion(restoreArea); PixelBlender blender = PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); - for (int y = frameY; y < frameY + frameHeight; y++) + for (int y = 0; y < restoreArea.Height; y++) { - Span srcPixelRow = srcPixels.DangerousGetRowSpan(y).Slice(frameX, frameWidth); - Span dstPixelRow = dstPixels.DangerousGetRowSpan(y).Slice(frameX, frameWidth); + Span srcPixelRow = srcPixels.DangerousGetRowSpan(y); + Span dstPixelRow = dstPixels.DangerousGetRowSpan(y); - blender.Blend(this.configuration, dstPixelRow, srcPixelRow, dstPixelRow, 1.0f); + blender.Blend(this.configuration, dstPixelRow, srcPixelRow, dstPixelRow, 1f); } } diff --git a/src/ImageSharp/Formats/Webp/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/WebpFrameData.cs index e2bcfd7c36..93c5d10dcd 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameData.cs @@ -53,6 +53,8 @@ internal struct WebpFrameData /// public WebpDisposalMethod DisposalMethod; + public readonly Rectangle Bounds => new((int)this.X * 2, (int)this.Y * 2, (int)this.Width, (int)this.Height); + /// /// Reads the animation frame header. /// From 296da738008b06ea511b4e0123d059aa4e660a89 Mon Sep 17 00:00:00 2001 From: Poker Date: Fri, 3 Nov 2023 14:26:50 +0800 Subject: [PATCH 021/219] add riif helper --- src/ImageSharp/Common/Helpers/RiffHelper.cs | 117 ++++++++++++++++++++ 1 file changed, 117 insertions(+) create mode 100644 src/ImageSharp/Common/Helpers/RiffHelper.cs diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Common/Helpers/RiffHelper.cs new file mode 100644 index 0000000000..6354ebd663 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/RiffHelper.cs @@ -0,0 +1,117 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using System.Text; + +namespace SixLabors.ImageSharp.Common.Helpers; + +internal class RiffHelper +{ + /// + /// The header bytes identifying RIFF file. + /// + public static readonly uint RiffFourCc = 0x52_49_46_46; + + public static void WriteRiffFile(Stream stream, string formType, Action func) => + WriteChunk(stream, RiffFourCc, s => + { + s.Write(Encoding.ASCII.GetBytes(formType)); + func(s); + }); + + public static void WriteChunk(Stream stream, uint fourCc, Action func) + { + Span buffer = stackalloc byte[4]; + + // write the fourCC + BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + stream.Write(buffer); + + long sizePosition = stream.Position; + stream.Position += 4; + + func(stream); + + long position = stream.Position; + stream.Position = sizePosition; + + uint dataSize = (uint)(position - sizePosition - 4); + + // padding + if (dataSize % 2 == 1) + { + stream.WriteByte(0); + position++; + } + + BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); + stream.Write(buffer); + + stream.Position = position; + } + + public static void WriteChunk(Stream stream, uint fourCc, ReadOnlySpan data) + { + Span buffer = stackalloc byte[4]; + + // write the fourCC + BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + stream.Write(buffer); + uint size = (uint)data.Length; + BinaryPrimitives.WriteUInt32LittleEndian(buffer, size); + stream.Write(buffer); + stream.Write(data); + + // padding + if (size % 2 == 1) + { + stream.WriteByte(0); + } + } + + public static unsafe void WriteChunk(Stream stream, uint fourCc, in TStruct chunk) + where TStruct : unmanaged + { + fixed (TStruct* ptr = &chunk) + { + WriteChunk(stream, fourCc, new Span(ptr, sizeof(TStruct))); + } + } + + public static long BeginWriteChunk(Stream stream, uint fourCc) + { + Span buffer = stackalloc byte[4]; + + // write the fourCC + BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + stream.Write(buffer); + + long sizePosition = stream.Position; + stream.Position += 4; + + return sizePosition; + } + + public static void EndWriteChunk(Stream stream, long sizePosition) + { + Span buffer = stackalloc byte[4]; + + long position = stream.Position; + stream.Position = sizePosition; + + uint dataSize = (uint)(position - sizePosition - 4); + + // padding + if (dataSize % 2 == 1) + { + stream.WriteByte(0); + position++; + } + + BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); + stream.Write(buffer); + + stream.Position = position; + } +} From 9dc0cda95e1c810f3bd56db1803fc0aa6cea4a09 Mon Sep 17 00:00:00 2001 From: Poker Date: Fri, 3 Nov 2023 15:06:57 +0800 Subject: [PATCH 022/219] add static --- src/ImageSharp/Common/Helpers/RiffHelper.cs | 17 +++++++++++++---- 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Common/Helpers/RiffHelper.cs index 6354ebd663..0395d9a9c9 100644 --- a/src/ImageSharp/Common/Helpers/RiffHelper.cs +++ b/src/ImageSharp/Common/Helpers/RiffHelper.cs @@ -6,12 +6,12 @@ using System.Text; namespace SixLabors.ImageSharp.Common.Helpers; -internal class RiffHelper +internal static class RiffHelper { /// /// The header bytes identifying RIFF file. /// - public static readonly uint RiffFourCc = 0x52_49_46_46; + private const uint RiffFourCc = 0x52_49_46_46; public static void WriteRiffFile(Stream stream, string formType, Action func) => WriteChunk(stream, RiffFourCc, s => @@ -64,7 +64,7 @@ internal class RiffHelper stream.Write(data); // padding - if (size % 2 == 1) + if (size % 2 is 1) { stream.WriteByte(0); } @@ -103,7 +103,7 @@ internal class RiffHelper uint dataSize = (uint)(position - sizePosition - 4); // padding - if (dataSize % 2 == 1) + if (dataSize % 2 is 1) { stream.WriteByte(0); position++; @@ -114,4 +114,13 @@ internal class RiffHelper stream.Position = position; } + + public static long BeginWriteRiffFile(Stream stream, string formType) + { + long sizePosition = BeginWriteChunk(stream, RiffFourCc); + stream.Write(Encoding.ASCII.GetBytes(formType)); + return sizePosition; + } + + public static void EndWriteRiffFile(Stream stream, long sizePosition) => EndWriteChunk(stream, sizePosition); } From 4beafcf65586ff2631fefd2d6b1aedc1422ab4c8 Mon Sep 17 00:00:00 2001 From: Poker Date: Fri, 3 Nov 2023 17:16:44 +0800 Subject: [PATCH 023/219] fix FourCC bug --- src/ImageSharp/Common/Helpers/RiffHelper.cs | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Common/Helpers/RiffHelper.cs index 0395d9a9c9..8f06e5886f 100644 --- a/src/ImageSharp/Common/Helpers/RiffHelper.cs +++ b/src/ImageSharp/Common/Helpers/RiffHelper.cs @@ -25,7 +25,7 @@ internal static class RiffHelper Span buffer = stackalloc byte[4]; // write the fourCC - BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc); stream.Write(buffer); long sizePosition = stream.Position; @@ -34,7 +34,6 @@ internal static class RiffHelper func(stream); long position = stream.Position; - stream.Position = sizePosition; uint dataSize = (uint)(position - sizePosition - 4); @@ -46,8 +45,8 @@ internal static class RiffHelper } BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); + stream.Position = sizePosition; stream.Write(buffer); - stream.Position = position; } @@ -56,7 +55,7 @@ internal static class RiffHelper Span buffer = stackalloc byte[4]; // write the fourCC - BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc); stream.Write(buffer); uint size = (uint)data.Length; BinaryPrimitives.WriteUInt32LittleEndian(buffer, size); @@ -84,7 +83,7 @@ internal static class RiffHelper Span buffer = stackalloc byte[4]; // write the fourCC - BinaryPrimitives.WriteUInt32LittleEndian(buffer, fourCc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, fourCc); stream.Write(buffer); long sizePosition = stream.Position; @@ -98,7 +97,6 @@ internal static class RiffHelper Span buffer = stackalloc byte[4]; long position = stream.Position; - stream.Position = sizePosition; uint dataSize = (uint)(position - sizePosition - 4); @@ -110,8 +108,8 @@ internal static class RiffHelper } BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); + stream.Position = sizePosition; stream.Write(buffer); - stream.Position = position; } From 1b0b877a147e81b9c3ff9d3e90de668b4e13cf1d Mon Sep 17 00:00:00 2001 From: Poker Date: Fri, 3 Nov 2023 19:18:56 +0800 Subject: [PATCH 024/219] introduce RiffHelper --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 222 ++---------------- .../Webp/Chunks/WebpAnimationParameter.cs | 37 +++ .../Formats/Webp/Chunks/WebpFrameData.cs | 140 +++++++++++ .../Formats/Webp/Chunks/WebpVp8X.cs | 113 +++++++++ .../Formats/Webp/Lossless/Vp8LEncoder.cs | 23 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 23 +- .../Formats/Webp/WebpAnimationDecoder.cs | 3 +- .../Formats/Webp/WebpChunkParsingUtils.cs | 18 +- src/ImageSharp/Formats/Webp/WebpChunkType.cs | 2 +- src/ImageSharp/Formats/Webp/WebpConstants.cs | 10 +- src/ImageSharp/Formats/Webp/WebpFrameData.cs | 93 -------- 11 files changed, 349 insertions(+), 335 deletions(-) create mode 100644 src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs create mode 100644 src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs create mode 100644 src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs delete mode 100644 src/ImageSharp/Formats/Webp/WebpFrameData.cs diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index cbf96a91af..d502fd6063 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -1,8 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Buffers.Binary; -using System.Runtime.InteropServices; +using System.Diagnostics; +using SixLabors.ImageSharp.Common.Helpers; +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -15,8 +16,6 @@ internal abstract class BitWriterBase private const ulong MaxCanvasPixels = 4294967295ul; - protected const uint ExtendedFileChunkSize = WebpConstants.ChunkHeaderSize + WebpConstants.Vp8XChunkSize; - /// /// Buffer to write to. /// @@ -79,48 +78,6 @@ internal abstract class BitWriterBase Array.Resize(ref this.buffer, newSize); } - /// - /// Writes the RIFF header to the stream. - /// - /// The stream to write to. - /// The block length. - protected static void WriteRiffHeader(Stream stream, uint riffSize) - { - stream.Write(WebpConstants.RiffFourCc); - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32LittleEndian(buf, riffSize); - stream.Write(buf); - stream.Write(WebpConstants.WebpHeader); - } - - /// - /// Calculates the chunk size of EXIF, XMP or ICCP metadata. - /// - /// The metadata profile bytes. - /// The metadata chunk size in bytes. - protected static uint MetadataChunkSize(byte[] metadataBytes) - { - uint metaSize = (uint)metadataBytes.Length; - return WebpConstants.ChunkHeaderSize + metaSize + (metaSize & 1); - } - - /// - /// Calculates the chunk size of a alpha chunk. - /// - /// The alpha chunk bytes. - /// The alpha data chunk size in bytes. - protected static uint AlphaChunkSize(Span alphaBytes) - { - uint alphaSize = (uint)alphaBytes.Length + 1; - return WebpConstants.ChunkHeaderSize + alphaSize + (alphaSize & 1); - } - - /// - /// Overwrites ides the write file size. - /// - /// The stream to write to. - protected static void OverwriteFileSize(Stream stream) => OverwriteFrameSize(stream, 4); - /// /// Write the trunks before data trunk. /// @@ -143,7 +100,9 @@ internal abstract class BitWriterBase bool hasAnimation) { // Write file size later - WriteRiffHeader(stream, 0); + long pos = RiffHelper.BeginWriteRiffFile(stream, WebpConstants.WebpFourCc); + + Debug.Assert(pos is 4, "Stream should be written from position 0."); // Write VP8X, header if necessary. bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha || hasAnimation; @@ -153,7 +112,7 @@ internal abstract class BitWriterBase if (iccProfile != null) { - WriteColorProfile(stream, iccProfile.ToByteArray()); + RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Iccp, iccProfile.ToByteArray()); } } } @@ -177,49 +136,17 @@ internal abstract class BitWriterBase { if (exifProfile != null) { - WriteMetadataProfile(stream, exifProfile.ToByteArray(), WebpChunkType.Exif); + RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Exif, exifProfile.ToByteArray()); } if (xmpProfile != null) { - WriteMetadataProfile(stream, xmpProfile.Data, WebpChunkType.Xmp); + RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Xmp, xmpProfile.Data); } - OverwriteFileSize(stream); - } - - /// - /// Writes a metadata profile (EXIF or XMP) to the stream. - /// - /// The stream to write to. - /// The metadata profile's bytes. - /// The chuck type to write. - protected static void WriteMetadataProfile(Stream stream, byte[]? metadataBytes, WebpChunkType chunkType) - { - DebugGuard.NotNull(metadataBytes, nameof(metadataBytes)); - - uint size = (uint)metadataBytes.Length; - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)chunkType); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, size); - stream.Write(buf); - stream.Write(metadataBytes); - - // Add padding byte if needed. - if ((size & 1) == 1) - { - stream.WriteByte(0); - } + RiffHelper.EndWriteRiffFile(stream, 4); } - /// - /// Writes the color profile() to the stream. - /// - /// The stream to write to. - /// The color profile bytes. - protected static void WriteColorProfile(Stream stream, byte[] iccProfileBytes) => WriteMetadataProfile(stream, iccProfileBytes, WebpChunkType.Iccp); - /// /// Writes the animation parameter() to the stream. /// @@ -233,55 +160,8 @@ internal abstract class BitWriterBase /// The number of times to loop the animation. If it is 0, this means infinitely. public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount) { - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.AnimationParameter); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, sizeof(uint) + sizeof(ushort)); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, background.ToRgba32().Rgba); - stream.Write(buf); - BinaryPrimitives.WriteUInt16LittleEndian(buf[..2], loopCount); - stream.Write(buf[..2]); - } - - /// - /// Writes the animation frame() to the stream. - /// - /// The stream to write to. - /// Animation frame data. - public static long WriteAnimationFrame(Stream stream, WebpFrameData animation) - { - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Animation); - stream.Write(buf); - long position = stream.Position; - BinaryPrimitives.WriteUInt32BigEndian(buf, 0); - stream.Write(buf); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.X); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Y); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Width - 1); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Height - 1); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, animation.Duration); - - byte flag = (byte)(((int)animation.BlendingMethod << 1) | (int)animation.DisposalMethod); - stream.WriteByte(flag); - return position; - } - - /// - /// Overwrites ides the write frame size. - /// - /// The stream to write to. - /// Previous position. - public static void OverwriteFrameSize(Stream stream, long prevPosition) - { - uint position = (uint)stream.Position; - stream.Position = prevPosition; - byte[] buffer = new byte[4]; - - BinaryPrimitives.WriteUInt32LittleEndian(buffer, (uint)(position - prevPosition - 4)); - stream.Write(buffer); - stream.Position = position; + WebpAnimationParameter chunk = new(background.ToRgba32().Rgba, loopCount); + chunk.WriteTo(stream); } /// @@ -292,27 +172,17 @@ internal abstract class BitWriterBase /// Indicates, if the alpha channel data is compressed. public static void WriteAlphaChunk(Stream stream, Span dataBytes, bool alphaDataIsCompressed) { - uint size = (uint)dataBytes.Length + 1; - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Alpha); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, size); - stream.Write(buf); - + long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.Alpha); byte flags = 0; if (alphaDataIsCompressed) { + // TODO: Filtering and preprocessing flags = 1; } stream.WriteByte(flags); stream.Write(dataBytes); - - // Add padding byte if needed. - if ((size & 1) == 1) - { - stream.WriteByte(0); - } + RiffHelper.EndWriteChunk(stream, pos); } /// @@ -328,66 +198,10 @@ internal abstract class BitWriterBase /// Flag indicating, if an animation parameter is present. protected static void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) { - if (width > MaxDimension || height > MaxDimension) - { - WebpThrowHelper.ThrowInvalidImageDimensions($"Image width or height exceeds maximum allowed dimension of {MaxDimension}"); - } + WebpVp8X chunk = new(hasAnimation, xmpProfile != null, exifProfile != null, hasAlpha, iccProfile != null, width, height); - // The spec states that the product of Canvas Width and Canvas Height MUST be at most 2^32 - 1. - if (width * height > MaxCanvasPixels) - { - WebpThrowHelper.ThrowInvalidImageDimensions("The product of image width and height MUST be at most 2^32 - 1"); - } - - uint flags = 0; - if (exifProfile != null) - { - // Set exif bit. - flags |= 8; - } - - if (hasAnimation) - { - // Set animated flag. - flags |= 2; - } - - if (xmpProfile != null) - { - // Set xmp bit. - flags |= 4; - } - - if (hasAlpha) - { - // Set alpha bit. - flags |= 16; - } - - if (iccProfile != null) - { - // Set iccp flag. - flags |= 32; - } - - Span buf = stackalloc byte[4]; - BinaryPrimitives.WriteUInt32BigEndian(buf, (uint)WebpChunkType.Vp8X); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, WebpConstants.Vp8XChunkSize); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, flags); - stream.Write(buf); - BinaryPrimitives.WriteUInt32LittleEndian(buf, width - 1); - stream.Write(buf[..3]); - BinaryPrimitives.WriteUInt32LittleEndian(buf, height - 1); - stream.Write(buf[..3]); - } - - private unsafe struct ScratchBuffer - { - private const int Size = 4; - private fixed byte scratch[Size]; + chunk.Validate(MaxDimension, MaxCanvasPixels); - public Span Span => MemoryMarshal.CreateSpan(ref this.scratch[0], Size); + chunk.WriteTo(stream); } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs new file mode 100644 index 0000000000..3855a293c1 --- /dev/null +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs @@ -0,0 +1,37 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using SixLabors.ImageSharp.Common.Helpers; + +namespace SixLabors.ImageSharp.Formats.Webp.Chunks; + +internal readonly struct WebpAnimationParameter +{ + public WebpAnimationParameter(uint background, ushort loopCount) + { + this.Background = background; + this.LoopCount = loopCount; + } + + /// + /// Gets default background color of the canvas in [Blue, Green, Red, Alpha] byte order. + /// This color MAY be used to fill the unused space on the canvas around the frames, + /// as well as the transparent pixels of the first frame. + /// The background color is also used when the Disposal method is 1. + /// + public uint Background { get; } + + /// + /// Gets number of times to loop the animation. If it is 0, this means infinitely. + /// + public ushort LoopCount { get; } + + public void WriteTo(Stream stream) + { + Span buffer = stackalloc byte[6]; + BinaryPrimitives.WriteUInt32LittleEndian(buffer[..4], this.Background); + BinaryPrimitives.WriteUInt16LittleEndian(buffer[4..], this.LoopCount); + RiffHelper.WriteChunk(stream, (uint)WebpChunkType.AnimationParameter, buffer); + } +} diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs new file mode 100644 index 0000000000..f22a3fd540 --- /dev/null +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -0,0 +1,140 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Common.Helpers; + +namespace SixLabors.ImageSharp.Formats.Webp.Chunks; + +internal readonly struct WebpFrameData +{ + /// + /// X(3) + Y(3) + Width(3) + Height(3) + Duration(3) + 1 byte for flags. + /// + public const uint HeaderSize = 16; + + public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, WebpBlendingMethod blendingMethod, WebpDisposalMethod disposalMethod) + { + this.DataSize = dataSize; + this.X = x; + this.Y = y; + this.Width = width; + this.Height = height; + this.Duration = duration; + this.DisposalMethod = disposalMethod; + this.BlendingMethod = blendingMethod; + } + + public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, int flags) + : this( + dataSize, + x, + y, + width, + height, + duration, + (flags & 2) != 0 ? WebpBlendingMethod.DoNotBlend : WebpBlendingMethod.AlphaBlending, + (flags & 1) == 1 ? WebpDisposalMethod.Dispose : WebpDisposalMethod.DoNotDispose) + { + } + + public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, WebpBlendingMethod blendingMethod, WebpDisposalMethod disposalMethod) + : this(0, x, y, width, height, duration, blendingMethod, disposalMethod) + { + } + + /// + /// Gets the animation chunk size. + /// + public uint DataSize { get; } + + /// + /// Gets the X coordinate of the upper left corner of the frame is Frame X * 2. + /// + public uint X { get; } + + /// + /// Gets the Y coordinate of the upper left corner of the frame is Frame Y * 2. + /// + public uint Y { get; } + + /// + /// Gets the width of the frame. + /// + public uint Width { get; } + + /// + /// Gets the height of the frame. + /// + public uint Height { get; } + + /// + /// Gets the time to wait before displaying the next frame, in 1 millisecond units. + /// Note the interpretation of frame duration of 0 (and often smaller then 10) is implementation defined. + /// + public uint Duration { get; } + + /// + /// Gets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. + /// + public WebpBlendingMethod BlendingMethod { get; } + + /// + /// Gets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. + /// + public WebpDisposalMethod DisposalMethod { get; } + + public Rectangle Bounds => new((int)this.X * 2, (int)this.Y * 2, (int)this.Width, (int)this.Height); + + /// + /// Writes the animation frame() to the stream. + /// + /// The stream to write to. + public long WriteHeaderTo(Stream stream) + { + byte flags = 0; + + if (this.BlendingMethod is WebpBlendingMethod.DoNotBlend) + { + // Set blending flag. + flags |= 2; + } + + if (this.DisposalMethod is WebpDisposalMethod.Dispose) + { + // Set disposal flag. + flags |= 1; + } + + long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.FrameData); + + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.X); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Y); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Width - 1); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Height - 1); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Duration); + stream.WriteByte(flags); + + return pos; + } + + /// + /// Reads the animation frame header. + /// + /// The stream to read from. + /// Animation frame data. + public static WebpFrameData Parse(Stream stream) + { + Span buffer = stackalloc byte[4]; + + WebpFrameData data = new( + dataSize: WebpChunkParsingUtils.ReadChunkSize(stream, buffer), + x: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + y: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + width: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, + height: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, + duration: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + flags: stream.ReadByte()); + + return data; + } +} diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs new file mode 100644 index 0000000000..70d6870ce4 --- /dev/null +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -0,0 +1,113 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Common.Helpers; + +namespace SixLabors.ImageSharp.Formats.Webp.Chunks; + +internal readonly struct WebpVp8X +{ + public WebpVp8X(bool hasAnimation, bool hasXmp, bool hasExif, bool hasAlpha, bool hasIcc, uint width, uint height) + { + this.HasAnimation = hasAnimation; + this.HasXmp = hasXmp; + this.HasExif = hasExif; + this.HasAlpha = hasAlpha; + this.HasIcc = hasIcc; + this.Width = width; + this.Height = height; + } + + /// + /// Gets a value indicating whether this is an animated image. Data in 'ANIM' and 'ANMF' Chunks should be used to control the animation. + /// + public bool HasAnimation { get; } + + /// + /// Gets a value indicating whether the file contains XMP metadata. + /// + public bool HasXmp { get; } + + /// + /// Gets a value indicating whether the file contains Exif metadata. + /// + public bool HasExif { get; } + + /// + /// Gets a value indicating whether any of the frames of the image contain transparency information ("alpha"). + /// + public bool HasAlpha { get; } + + /// + /// Gets a value indicating whether the file contains an 'ICCP' Chunk. + /// + public bool HasIcc { get; } + + /// + /// Gets width of the canvas in pixels. (uint24) + /// + public uint Width { get; } + + /// + /// Gets height of the canvas in pixels. (uint24) + /// + public uint Height { get; } + + public void Validate(uint maxDimension, ulong maxCanvasPixels) + { + if (this.Width > maxDimension || this.Height > maxDimension) + { + WebpThrowHelper.ThrowInvalidImageDimensions($"Image width or height exceeds maximum allowed dimension of {maxDimension}"); + } + + // The spec states that the product of Canvas Width and Canvas Height MUST be at most 2^32 - 1. + if (this.Width * this.Height > maxCanvasPixels) + { + WebpThrowHelper.ThrowInvalidImageDimensions("The product of image width and height MUST be at most 2^32 - 1"); + } + } + + public void WriteTo(Stream stream) + { + byte flags = 0; + + if (this.HasAnimation) + { + // Set animated flag. + flags |= 2; + } + + if (this.HasXmp) + { + // Set xmp bit. + flags |= 4; + } + + if (this.HasExif) + { + // Set exif bit. + flags |= 8; + } + + if (this.HasAlpha) + { + // Set alpha bit. + flags |= 16; + } + + if (this.HasIcc) + { + // Set icc flag. + flags |= 32; + } + + long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.Vp8X); + + stream.WriteByte(flags); + stream.Position += 3; // Reserved bytes + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Width - 1); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Height - 1); + + RiffHelper.EndWriteChunk(stream, pos); + } +} diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 42aa667ac5..fe0131a2aa 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -6,7 +6,9 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -308,16 +310,15 @@ internal class Vp8LEncoder : IDisposable WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData - { - X = 0, - Y = 0, - Width = (uint)frame.Width, - Height = (uint)frame.Height, - Duration = frameMetadata.FrameDelay, - BlendingMethod = frameMetadata.BlendMethod, - DisposalMethod = frameMetadata.DisposalMethod - }); + prevPosition = new WebpFrameData( + 0, + 0, + (uint)frame.Width, + (uint)frame.Height, + frameMetadata.FrameDelay, + frameMetadata.BlendMethod, + frameMetadata.DisposalMethod) + .WriteHeaderTo(stream); } // Write bytes from the bitwriter buffer to the stream. @@ -325,7 +326,7 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - BitWriterBase.OverwriteFrameSize(stream, prevPosition); + RiffHelper.EndWriteChunk(stream, prevPosition); } } diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 3b73023062..98e50bb9c2 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -4,7 +4,9 @@ using System.Buffers; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -478,16 +480,15 @@ internal class Vp8Encoder : IDisposable WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. - prevPosition = BitWriterBase.WriteAnimationFrame(stream, new WebpFrameData - { - X = 0, - Y = 0, - Width = (uint)frame.Width, - Height = (uint)frame.Height, - Duration = frameMetadata.FrameDelay, - BlendingMethod = frameMetadata.BlendMethod, - DisposalMethod = frameMetadata.DisposalMethod - }); + prevPosition = new WebpFrameData( + 0, + 0, + (uint)frame.Width, + (uint)frame.Height, + frameMetadata.FrameDelay, + frameMetadata.BlendMethod, + frameMetadata.DisposalMethod) + .WriteHeaderTo(stream); } if (hasAlpha) @@ -501,7 +502,7 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - BitWriterBase.OverwriteFrameSize(stream, prevPosition); + RiffHelper.EndWriteChunk(stream, prevPosition); } } finally diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index fad6ca16cc..f0e4093194 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers; +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; @@ -99,7 +100,7 @@ internal class WebpAnimationDecoder : IDisposable remainingBytes -= 4; switch (chunkType) { - case WebpChunkType.Animation: + case WebpChunkType.FrameData: Color backgroundColor = this.backgroundColorHandling == BackgroundColorHandling.Ignore ? new Color(new Bgra32(0, 0, 0, 0)) : features.AnimationBackgroundColor!.Value; diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index f4e40090cf..80ffe8a996 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -106,14 +106,14 @@ internal static class WebpChunkParsingUtils WebpThrowHelper.ThrowImageFormatException("bad partition length"); } - Vp8FrameHeader vp8FrameHeader = new Vp8FrameHeader + Vp8FrameHeader vp8FrameHeader = new() { KeyFrame = true, Profile = (sbyte)version, PartitionLength = partitionLength }; - Vp8BitReader bitReader = new Vp8BitReader(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; + Vp8BitReader bitReader = new(stream, remaining, memoryAllocator, partitionLength) { Remaining = remaining }; return new WebpImageInfo { @@ -139,7 +139,7 @@ internal static class WebpChunkParsingUtils // VP8 data size. uint imageDataSize = ReadChunkSize(stream, buffer); - Vp8LBitReader bitReader = new Vp8LBitReader(stream, imageDataSize, memoryAllocator); + Vp8LBitReader bitReader = new(stream, imageDataSize, memoryAllocator); // One byte signature, should be 0x2f. uint signature = bitReader.ReadValue(8); @@ -231,7 +231,7 @@ internal static class WebpChunkParsingUtils uint height = ReadUInt24LittleEndian(stream, buffer) + 1; // Read all the chunks in the order they occur. - WebpImageInfo info = new WebpImageInfo + WebpImageInfo info = new() { Width = width, Height = height, @@ -247,7 +247,7 @@ internal static class WebpChunkParsingUtils /// The stream to read from. /// The buffer to store the read data into. /// A unsigned 24 bit integer. - public static uint ReadUInt24LittleEndian(BufferedReadStream stream, Span buffer) + public static uint ReadUInt24LittleEndian(Stream stream, Span buffer) { if (stream.Read(buffer, 0, 3) == 3) { @@ -286,14 +286,14 @@ internal static class WebpChunkParsingUtils /// The stream to read the data from. /// Buffer to store the data read from the stream. /// The chunk size in bytes. - public static uint ReadChunkSize(BufferedReadStream stream, Span buffer) + public static uint ReadChunkSize(Stream stream, Span buffer) { - DebugGuard.IsTrue(buffer.Length == 4, "buffer has wrong length"); + DebugGuard.IsTrue(buffer.Length is 4, "buffer has wrong length"); - if (stream.Read(buffer) == 4) + if (stream.Read(buffer) is 4) { uint chunkSize = BinaryPrimitives.ReadUInt32LittleEndian(buffer); - return chunkSize % 2 == 0 ? chunkSize : chunkSize + 1; + return chunkSize % 2 is 0 ? chunkSize : chunkSize + 1; } throw new ImageFormatException("Invalid Webp data, could not read chunk size."); diff --git a/src/ImageSharp/Formats/Webp/WebpChunkType.cs b/src/ImageSharp/Formats/Webp/WebpChunkType.cs index 5836dc6c09..12e3297775 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkType.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkType.cs @@ -61,5 +61,5 @@ internal enum WebpChunkType : uint /// For animated images, this chunk contains information about a single frame. If the Animation flag is not set, then this chunk SHOULD NOT be present. /// /// ANMF (Multiple) - Animation = 0x414E4D46, + FrameData = 0x414E4D46, } diff --git a/src/ImageSharp/Formats/Webp/WebpConstants.cs b/src/ImageSharp/Formats/Webp/WebpConstants.cs index 1433772757..818c843ea9 100644 --- a/src/ImageSharp/Formats/Webp/WebpConstants.cs +++ b/src/ImageSharp/Formats/Webp/WebpConstants.cs @@ -55,6 +55,11 @@ internal static class WebpConstants 0x50 // P }; + /// + /// The header bytes identifying a Webp. + /// + public const string WebpFourCc = "WEBP"; + /// /// 3 bits reserved for version. /// @@ -70,11 +75,6 @@ internal static class WebpConstants /// public const int Vp8FrameHeaderSize = 10; - /// - /// Size of a VP8X chunk in bytes. - /// - public const int Vp8XChunkSize = 10; - /// /// Size of a chunk header. /// diff --git a/src/ImageSharp/Formats/Webp/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/WebpFrameData.cs deleted file mode 100644 index 93c5d10dcd..0000000000 --- a/src/ImageSharp/Formats/Webp/WebpFrameData.cs +++ /dev/null @@ -1,93 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.IO; - -namespace SixLabors.ImageSharp.Formats.Webp; - -internal struct WebpFrameData -{ - /// - /// The animation chunk size. - /// - public uint DataSize; - - /// - /// X(3) + Y(3) + Width(3) + Height(3) + Duration(3) + 1 byte for flags. - /// - public const uint HeaderSize = 16; - - /// - /// The X coordinate of the upper left corner of the frame is Frame X * 2. - /// - public uint X; - - /// - /// The Y coordinate of the upper left corner of the frame is Frame Y * 2. - /// - public uint Y; - - /// - /// The width of the frame. - /// - public uint Width; - - /// - /// The height of the frame. - /// - public uint Height; - - /// - /// The time to wait before displaying the next frame, in 1 millisecond units. - /// Note the interpretation of frame duration of 0 (and often smaller then 10) is implementation defined. - /// - public uint Duration; - - /// - /// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. - /// - public WebpBlendingMethod BlendingMethod; - - /// - /// Indicates how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. - /// - public WebpDisposalMethod DisposalMethod; - - public readonly Rectangle Bounds => new((int)this.X * 2, (int)this.Y * 2, (int)this.Width, (int)this.Height); - - /// - /// Reads the animation frame header. - /// - /// The stream to read from. - /// Animation frame data. - public static WebpFrameData Parse(BufferedReadStream stream) - { - Span buffer = stackalloc byte[4]; - - WebpFrameData data = new() - { - DataSize = WebpChunkParsingUtils.ReadChunkSize(stream, buffer), - - // 3 bytes for the X coordinate of the upper left corner of the frame. - X = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), - - // 3 bytes for the Y coordinate of the upper left corner of the frame. - Y = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), - - // Frame width Minus One. - Width = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, - - // Frame height Minus One. - Height = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, - - // Frame duration. - Duration = WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) - }; - - byte flags = (byte)stream.ReadByte(); - data.DisposalMethod = (flags & 1) == 1 ? WebpDisposalMethod.Dispose : WebpDisposalMethod.DoNotDispose; - data.BlendingMethod = (flags & (1 << 1)) != 0 ? WebpBlendingMethod.DoNotBlend : WebpBlendingMethod.AlphaBlending; - - return data; - } -} From a477ac13bc358811cd4bb83c6ff0f19621f51ae5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 6 Nov 2023 21:21:11 +1000 Subject: [PATCH 025/219] Use correct alpha blending --- .../Formats/Webp/WebpAnimationDecoder.cs | 64 +++++++++---------- .../Formats/WebP/WebpDecoderTests.cs | 10 +++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Webp/landscape.webp | 3 + 4 files changed, 45 insertions(+), 33 deletions(-) create mode 100644 tests/Images/Input/Webp/landscape.webp diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index f0e4093194..66e69d9a43 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -200,13 +200,10 @@ internal class WebpAnimationDecoder : IDisposable this.RestoreToBackground(imageFrame, backgroundColor); } - using Buffer2D decodedImage = this.DecodeImageData(frameData, webpInfo); - DrawDecodedImageOnCanvas(decodedImage, imageFrame, regionRectangle); + using Buffer2D decodedImageFrame = this.DecodeImageFrameData(frameData, webpInfo); - if (previousFrame != null && frameData.BlendingMethod is WebpBlendingMethod.AlphaBlending) - { - this.AlphaBlend(previousFrame, imageFrame, regionRectangle); - } + bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendingMethod.AlphaBlending; + DrawDecodedImageFrameOnCanvas(decodedImageFrame, imageFrame, regionRectangle, blend); previousFrame = currentFrame ?? image.Frames.RootFrame; this.restoreArea = regionRectangle; @@ -253,7 +250,7 @@ internal class WebpAnimationDecoder : IDisposable /// The frame data. /// The webp information. /// A decoded image. - private Buffer2D DecodeImageData(WebpFrameData frameData, WebpImageInfo webpInfo) + private Buffer2D DecodeImageFrameData(WebpFrameData frameData, WebpImageInfo webpInfo) where TPixel : unmanaged, IPixel { ImageFrame decodedFrame = new(Configuration.Default, (int)frameData.Width, (int)frameData.Height); @@ -291,42 +288,43 @@ internal class WebpAnimationDecoder : IDisposable /// Draws the decoded image on canvas. The decoded image can be smaller the canvas. /// /// The type of the pixel. - /// The decoded image. + /// The decoded image. /// The image frame to draw into. /// The area of the frame. - private static void DrawDecodedImageOnCanvas(Buffer2D decodedImage, ImageFrame imageFrame, Rectangle restoreArea) + /// Whether to blend the decoded frame data onto the target frame. + private static void DrawDecodedImageFrameOnCanvas( + Buffer2D decodedImageFrame, + ImageFrame imageFrame, + Rectangle restoreArea, + bool blend) where TPixel : unmanaged, IPixel { + // Trim the destination frame to match the restore area. The source frame is already trimmed. Buffer2DRegion imageFramePixels = imageFrame.PixelBuffer.GetRegion(restoreArea); - int decodedRowIdx = 0; - for (int y = 0; y < restoreArea.Height; y++) + if (blend) { - Span framePixelRow = imageFramePixels.DangerousGetRowSpan(y); - Span decodedPixelRow = decodedImage.DangerousGetRowSpan(decodedRowIdx++)[..restoreArea.Width]; - decodedPixelRow.TryCopyTo(framePixelRow); + // The destination frame has already been prepopulated with the pixel data from the previous frame + // so blending will leave the desired result which takes into consideration restoration to the + // background color within the restore area. + PixelBlender blender = + PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); + + for (int y = 0; y < restoreArea.Height; y++) + { + Span framePixelRow = imageFramePixels.DangerousGetRowSpan(y); + Span decodedPixelRow = decodedImageFrame.DangerousGetRowSpan(y)[..restoreArea.Width]; + + blender.Blend(imageFrame.Configuration, framePixelRow, framePixelRow, decodedPixelRow, 1f); + } + + return; } - } - /// - /// After disposing of the previous frame, render the current frame on the canvas using alpha-blending. - /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle. - /// - /// The pixel format. - /// The source image. - /// The destination image. - /// The area of the frame. - private void AlphaBlend(ImageFrame src, ImageFrame dst, Rectangle restoreArea) - where TPixel : unmanaged, IPixel - { - Buffer2DRegion srcPixels = src.PixelBuffer.GetRegion(restoreArea); - Buffer2DRegion dstPixels = dst.PixelBuffer.GetRegion(restoreArea); - PixelBlender blender = PixelOperations.Instance.GetPixelBlender(PixelColorBlendingMode.Normal, PixelAlphaCompositionMode.SrcOver); for (int y = 0; y < restoreArea.Height; y++) { - Span srcPixelRow = srcPixels.DangerousGetRowSpan(y); - Span dstPixelRow = dstPixels.DangerousGetRowSpan(y); - - blender.Blend(this.configuration, dstPixelRow, srcPixelRow, dstPixelRow, 1f); + Span framePixelRow = imageFramePixels.DangerousGetRowSpan(y); + Span decodedPixelRow = decodedImageFrame.DangerousGetRowSpan(y)[..restoreArea.Width]; + decodedPixelRow.CopyTo(framePixelRow); } } diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index c3a777c153..4b03671e16 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -357,6 +357,16 @@ public class WebpDecoderTests image.CompareToOriginal(provider, ReferenceDecoder); } + [Theory] + [WithFile(Lossy.AnimatedLandscape, PixelTypes.Rgba32)] + public void Decode_AnimatedLossy_AlphaBlending_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(WebpDecoder.Instance); + image.DebugSaveMultiFrame(provider); + image.CompareToOriginalMultiFrame(provider, ImageComparer.Exact); + } + [Theory] [WithFile(Lossless.LossLessCorruptImage1, PixelTypes.Rgba32)] [WithFile(Lossless.LossLessCorruptImage2, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 048b19dc5b..6ad93adfbd 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -681,6 +681,7 @@ public static class TestImages public static class Lossy { + public const string AnimatedLandscape = "Webp/landscape.webp"; public const string Earth = "Webp/earth_lossy.webp"; public const string WithExif = "Webp/exif_lossy.webp"; public const string WithExifNotEnoughData = "Webp/exif_lossy_not_enough_data.webp"; diff --git a/tests/Images/Input/Webp/landscape.webp b/tests/Images/Input/Webp/landscape.webp new file mode 100644 index 0000000000..5f1f31a055 --- /dev/null +++ b/tests/Images/Input/Webp/landscape.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:1e9f8b7ee87ecb59d8cee5e84320da7670eb5e274e1c0a7dd5f13fe3675be62a +size 26892 From f46137847bed3d6c63f1b1f29bf8538aa7a384b2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 6 Nov 2023 21:42:20 +1000 Subject: [PATCH 026/219] Complete encoding tests --- .../Formats/WebP/WebpEncoderTests.cs | 32 +++++++++++++++---- ...Encode_AnimatedLossy_Rgba32_landscape.webp | 3 ++ ...imatedLossy_Rgba32_leo_animated_lossy.webp | 3 ++ 3 files changed, 31 insertions(+), 7 deletions(-) create mode 100644 tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_landscape.webp create mode 100644 tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_leo_animated_lossy.webp diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index d81c9eb93a..0ad684b277 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -24,22 +23,41 @@ public class WebpEncoderTests where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - using MemoryStream memStream = new(); - image.SaveAsWebp(memStream, new() { FileFormat = WebpFileFormatType.Lossless }); + WebpEncoder encoder = new() + { + FileFormat = WebpFileFormatType.Lossless, + Quality = 100 + }; + + // Always save as we need to compare the encoded output. + provider.Utility.SaveTestOutputFile(image, "webp", encoder); - // TODO: DebugSave, VerifySimilarity + // Compare encoded result + image.VerifyEncoder(provider, "webp", string.Empty, encoder); } [Theory] [WithFile(Lossy.Animated, PixelTypes.Rgba32)] + [WithFile(Lossy.AnimatedLandscape, PixelTypes.Rgba32)] public void Encode_AnimatedLossy(TestImageProvider provider) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - using MemoryStream memStream = new(); - image.SaveAsWebp(memStream, new()); + WebpEncoder encoder = new() + { + FileFormat = WebpFileFormatType.Lossy, + Quality = 100 + }; + + // Always save as we need to compare the encoded output. + provider.Utility.SaveTestOutputFile(image, "webp", encoder); - // TODO: DebugSave, VerifySimilarity + // Compare encoded result + // The reference decoder seems to produce differences up to 0.1% but the input/output have been + // checked to be correct. + string path = provider.Utility.GetTestOutputFileName("webp", null, true); + using Image encoded = Image.Load(path); + encoded.CompareToReferenceOutput(ImageComparer.Tolerant(0.01f), provider, null, "webp"); } [Theory] diff --git a/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_landscape.webp b/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_landscape.webp new file mode 100644 index 0000000000..2312cb8576 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_landscape.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f9ece3c7acc6f40318e3cda6b0189607df6b9b60dd112212c72ec0f6aa26431d +size 409346 diff --git a/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_leo_animated_lossy.webp b/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_leo_animated_lossy.webp new file mode 100644 index 0000000000..8474504da7 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/WebpEncoderTests/Encode_AnimatedLossy_Rgba32_leo_animated_lossy.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:71800dff476f50ebd2a3d0cf0b4f5bef427a1c2cd8732b415511f10d3d93f9a0 +size 126382 From 72b80132416a88873f5f836b32d0ef718cb1a4f9 Mon Sep 17 00:00:00 2001 From: Sven Claesson Date: Fri, 10 Nov 2023 13:42:25 +0100 Subject: [PATCH 027/219] refactor PngDecoder to SpecializedImageDecoder --- src/ImageSharp/Formats/Png/PngDecoder.cs | 17 ++++++---- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 32 ++++++++++++------- .../Formats/Png/PngDecoderOptions.cs | 19 +++++++++++ .../Formats/Png/PngDecoderTests.cs | 11 +++++++ .../ReferenceCodecs/MagickReferenceDecoder.cs | 5 +++ 5 files changed, 66 insertions(+), 18 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngDecoderOptions.cs diff --git a/src/ImageSharp/Formats/Png/PngDecoder.cs b/src/ImageSharp/Formats/Png/PngDecoder.cs index d226451389..4a7ba3f961 100644 --- a/src/ImageSharp/Formats/Png/PngDecoder.cs +++ b/src/ImageSharp/Formats/Png/PngDecoder.cs @@ -8,7 +8,7 @@ namespace SixLabors.ImageSharp.Formats.Png; /// /// Decoder for generating an image out of a png encoded stream. /// -public sealed class PngDecoder : ImageDecoder +public sealed class PngDecoder : SpecializedImageDecoder { private PngDecoder() { @@ -25,31 +25,31 @@ public sealed class PngDecoder : ImageDecoder Guard.NotNull(options, nameof(options)); Guard.NotNull(stream, nameof(stream)); - return new PngDecoderCore(options).Identify(options.Configuration, stream, cancellationToken); + return new PngDecoderCore(new PngDecoderOptions() { GeneralOptions = options }).Identify(options.Configuration, stream, cancellationToken); } /// - protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + protected override Image Decode(PngDecoderOptions options, Stream stream, CancellationToken cancellationToken) { Guard.NotNull(options, nameof(options)); Guard.NotNull(stream, nameof(stream)); PngDecoderCore decoder = new(options); - Image image = decoder.Decode(options.Configuration, stream, cancellationToken); + Image image = decoder.Decode(options.GeneralOptions.Configuration, stream, cancellationToken); - ScaleToTargetSize(options, image); + ScaleToTargetSize(options.GeneralOptions, image); return image; } /// - protected override Image Decode(DecoderOptions options, Stream stream, CancellationToken cancellationToken) + protected override Image Decode(PngDecoderOptions options, Stream stream, CancellationToken cancellationToken) { Guard.NotNull(options, nameof(options)); Guard.NotNull(stream, nameof(stream)); PngDecoderCore decoder = new(options, true); - ImageInfo info = decoder.Identify(options.Configuration, stream, cancellationToken); + ImageInfo info = decoder.Identify(options.GeneralOptions.Configuration, stream, cancellationToken); stream.Position = 0; PngMetadata meta = info.Metadata.GetPngMetadata(); @@ -99,4 +99,7 @@ public sealed class PngDecoder : ImageDecoder return this.Decode(options, stream, cancellationToken); } } + + /// + protected override PngDecoderOptions CreateDefaultSpecializedOptions(DecoderOptions options) => new PngDecoderOptions() { GeneralOptions = options }; } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d8305a3f57..0957a7bd53 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -113,27 +113,34 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// private PngChunk? nextChunk; + /// + /// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored. + /// + private bool ignoreCrcErrors; + /// /// Initializes a new instance of the class. /// /// The decoder options. - public PngDecoderCore(DecoderOptions options) + public PngDecoderCore(PngDecoderOptions options) { - this.Options = options; - this.configuration = options.Configuration; - this.maxFrames = options.MaxFrames; - this.skipMetadata = options.SkipMetadata; + this.Options = options.GeneralOptions; + this.configuration = options.GeneralOptions.Configuration; + this.maxFrames = options.GeneralOptions.MaxFrames; + this.skipMetadata = options.GeneralOptions.SkipMetadata; this.memoryAllocator = this.configuration.MemoryAllocator; + this.ignoreCrcErrors = options.IgnoreCrcCheck; } - internal PngDecoderCore(DecoderOptions options, bool colorMetadataOnly) + internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly) { - this.Options = options; + this.Options = options.GeneralOptions; this.colorMetadataOnly = colorMetadataOnly; - this.maxFrames = options.MaxFrames; + this.maxFrames = options.GeneralOptions.MaxFrames; this.skipMetadata = true; - this.configuration = options.Configuration; + this.configuration = options.GeneralOptions.Configuration; this.memoryAllocator = this.configuration.MemoryAllocator; + this.ignoreCrcErrors = options.IgnoreCrcCheck; } /// @@ -1789,8 +1796,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals type: type, data: this.ReadChunkData(length)); - this.ValidateChunk(chunk, buffer); - + if (!this.ignoreCrcErrors) + { + this.ValidateChunk(chunk, buffer); + } + // Restore the stream position for IDAT and fdAT chunks, because it will be decoded later and // was only read to verifying the CRC is correct. if (type is PngChunkType.Data or PngChunkType.FrameData) diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs new file mode 100644 index 0000000000..c952a18ef2 --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs @@ -0,0 +1,19 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Png; + +/// +/// Configuration options for decoding png images. +/// +public sealed class PngDecoderOptions : ISpecializedDecoderOptions +{ + /// + public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions(); + + /// + /// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored. + /// Similar to PNG_CRC_QUIET_USE in libpng. + /// + public bool IgnoreCrcCheck { get; init; } +} diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 2e11093db6..a2925d254e 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -470,6 +470,17 @@ public partial class PngDecoderTests Assert.Contains("CRC Error. PNG IDAT chunk is corrupt!", ex.Message); } + [Theory] + [WithFile(TestImages.Png.Bad.WrongCrcDataChunk, PixelTypes.Rgba32)] + public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { IgnoreCrcCheck = true }); + + image.DebugSave(provider); + image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); + } + // https://github.com/SixLabors/ImageSharp/issues/1014 [Theory] [WithFileCollection(nameof(TestImagesIssue1014), PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs index ae09c4f3f2..80b5536ebd 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ReferenceCodecs/MagickReferenceDecoder.cs @@ -31,12 +31,17 @@ public class MagickReferenceDecoder : ImageDecoder { IgnoreFileSize = !this.validate }; + PngReadDefines pngReadDefines = new() + { + IgnoreCrc = !this.validate + }; MagickReadSettings settings = new() { FrameCount = (int)options.MaxFrames }; settings.SetDefines(bmpReadDefines); + settings.SetDefines(pngReadDefines); using MagickImageCollection magickImageCollection = new(stream, settings); List> framesList = new(); From 0c30a08b8152c2509cc79e86aa6e0606ac864490 Mon Sep 17 00:00:00 2001 From: Sven Claesson Date: Fri, 10 Nov 2023 14:12:24 +0100 Subject: [PATCH 028/219] fix old copy paste issue --- tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs index 74c7fc1d09..324bd4783a 100644 --- a/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs +++ b/tests/ImageSharp.Tests/Formats/ImageFormatManagerTests.cs @@ -43,7 +43,7 @@ public class ImageFormatManagerTests Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); - Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); + Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); Assert.Equal(1, this.DefaultFormatsManager.ImageDecoders.Select(item => item.Value).OfType().Count()); From 328e0465db6dfa46bc90d93eedb6fc4f85eec86f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 15 Nov 2023 12:40:49 +1000 Subject: [PATCH 029/219] Wire up connectors and gif encoder --- .../Formats/AnimatedImageFrameMetadata.cs | 93 +++++++++++++++++++ .../Formats/AnimatedImageMetadata.cs | 32 +++++++ src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 70 ++++++++++++-- .../Formats/Gif/GifFrameMetadata.cs | 40 ++++++++ src/ImageSharp/Formats/Gif/GifMetadata.cs | 26 ++++++ .../Formats/Gif/MetadataExtensions.cs | 44 ++++++++- .../Formats/Png/Chunks/AnimationControl.cs | 14 +-- .../Formats/Png/MetadataExtensions.cs | 48 +++++++++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 +- .../Formats/Png/PngDisposalMethod.cs | 6 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 +- src/ImageSharp/Formats/Png/PngMetadata.cs | 3 +- .../Formats/Webp/BitWriter/BitWriterBase.cs | 2 +- .../Formats/Webp/Chunks/WebpFrameData.cs | 8 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 2 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 2 +- .../Formats/Webp/MetadataExtensions.cs | 48 ++++++++++ .../Formats/Webp/WebpAnimationDecoder.cs | 6 +- .../Formats/Webp/WebpBlendingMethod.cs | 12 +-- .../Formats/Webp/WebpDisposalMethod.cs | 4 +- src/ImageSharp/Formats/Webp/WebpMetadata.cs | 14 +-- src/ImageSharp/Metadata/FrameDecodingMode.cs | 20 ---- src/ImageSharp/Metadata/ImageMetadata.cs | 26 ++++++ .../Formats/Gif/GifEncoderTests.cs | 4 +- .../Formats/Png/PngEncoderTests.cs | 5 + .../Formats/Png/PngFrameMetadataTests.cs | 4 +- .../Formats/WebP/WebpDecoderTests.cs | 4 +- 27 files changed, 465 insertions(+), 80 deletions(-) create mode 100644 src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs create mode 100644 src/ImageSharp/Formats/AnimatedImageMetadata.cs delete mode 100644 src/ImageSharp/Metadata/FrameDecodingMode.cs diff --git a/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs new file mode 100644 index 0000000000..5f4015180b --- /dev/null +++ b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs @@ -0,0 +1,93 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; +internal class AnimatedImageFrameMetadata +{ + /// + /// Gets or sets the frame color table. + /// + public ReadOnlyMemory? ColorTable { get; set; } + + /// + /// Gets or sets the frame color table mode. + /// + public FrameColorTableMode ColorTableMode { get; set; } + + /// + /// Gets or sets the duration of the frame. + /// + public TimeSpan Duration { get; set; } + + /// + /// Gets or sets the frame alpha blending mode. + /// + public FrameBlendMode BlendMode { get; set; } + + /// + /// Gets or sets the frame disposal mode. + /// + public FrameDisposalMode DisposalMode { get; set; } +} + +#pragma warning disable SA1201 // Elements should appear in the correct order +internal enum FrameBlendMode +#pragma warning restore SA1201 // Elements should appear in the correct order +{ + /// + /// Do not blend. Render the current frame on the canvas by overwriting the rectangle covered by the current frame. + /// + Source = 0, + + /// + /// Blend the current frame with the previous frame in the animation sequence within the rectangle covered + /// by the current frame. + /// If the current has any transparent areas, the corresponding areas of the previous frame will be visible + /// through these transparent regions. + /// + Over = 1 +} + +internal enum FrameDisposalMode +{ + /// + /// No disposal specified. + /// The decoder is not required to take any action. + /// + Unspecified = 0, + + /// + /// Do not dispose. The current frame is not disposed of, or in other words, not cleared or altered when moving to + /// the next frame. This means that the next frame is drawn over the current frame, and if the next frame contains + /// transparency, the previous frame will be visible through these transparent areas. + /// + DoNotDispose = 1, + + /// + /// Restore to background color. When transitioning to the next frame, the area occupied by the current frame is + /// filled with the background color specified in the image metadata. + /// This effectively erases the current frame by replacing it with the background color before the next frame is displayed. + /// + RestoreToBackground = 2, + + /// + /// Restore to previous. This method restores the area affected by the current frame to what it was before the + /// current frame was displayed. It essentially "undoes" the current frame, reverting to the state of the image + /// before the frame was displayed, then the next frame is drawn. This is useful for animations where only a small + /// part of the image changes from frame to frame. + /// + RestoreToPrevious = 3 +} + +internal enum FrameColorTableMode +{ + /// + /// The frame uses the shared color table specified by the image metadata. + /// + Global, + + /// + /// The frame uses a color table specified by the frame metadata. + /// + Local +} diff --git a/src/ImageSharp/Formats/AnimatedImageMetadata.cs b/src/ImageSharp/Formats/AnimatedImageMetadata.cs new file mode 100644 index 0000000000..d89ec41f07 --- /dev/null +++ b/src/ImageSharp/Formats/AnimatedImageMetadata.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats; +internal class AnimatedImageMetadata +{ + /// + /// Gets or sets the shared color table. + /// + public ReadOnlyMemory? ColorTable { get; set; } + + /// + /// Gets or sets the shared color table mode. + /// + public FrameColorTableMode ColorTableMode { get; set; } + + /// + /// Gets or sets the default background color of the canvas when animating. + /// This color may be used to fill the unused space on the canvas around the frames, + /// as well as the transparent pixels of the first frame. + /// The background color is also used when the disposal mode is . + /// + public Color BackgroundColor { get; set; } + + /// + /// Gets or sets the number of times any animation is repeated. + /// + /// 0 means to repeat indefinitely, count is set as repeat n-1 times. Defaults to 1. + /// + /// + public ushort RepeatCount { get; set; } +} diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 926cc091c7..33942ce547 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -8,6 +8,8 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -86,8 +88,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); - ImageMetadata metadata = image.Metadata; - GifMetadata gifMetadata = metadata.GetGifMetadata(); + GifMetadata gifMetadata = GetGifMetadata(image); this.colorTableMode ??= gifMetadata.ColorTableMode; bool useGlobalTable = this.colorTableMode == GifColorTableMode.Global; @@ -96,7 +97,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // Work out if there is an explicit transparent index set for the frame. We use that to ensure the // correct value is set for the background index when quantizing. - image.Frames.RootFrame.Metadata.TryGetGifMetadata(out GifFrameMetadata? frameMetadata); + GifFrameMetadata? frameMetadata = GetGifFrameMetadata(image.Frames.RootFrame, -1); int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); if (this.quantizer is null) @@ -140,7 +141,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // Get the number of bits. int bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); - this.WriteLogicalScreenDescriptor(metadata, image.Width, image.Height, backgroundIndex, useGlobalTable, bitDepth, stream); + this.WriteLogicalScreenDescriptor(image.Metadata, image.Width, image.Height, backgroundIndex, useGlobalTable, bitDepth, stream); if (useGlobalTable) { @@ -164,15 +165,69 @@ internal sealed class GifEncoderCore : IImageEncoderInternals quantized.Dispose(); - this.EncodeAdditionalFrames(stream, image, globalPalette); + this.EncodeAdditionalFrames(stream, image, globalPalette, transparencyIndex); stream.WriteByte(GifConstants.EndIntroducer); } + private static GifMetadata GetGifMetadata(Image image) + where TPixel : unmanaged, IPixel + { + if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) + { + return gif; + } + + if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) + { + AnimatedImageMetadata ani = png.ToAnimatedImageMetadata(); + return GifMetadata.FromAnimatedMetadata(ani); + } + + if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) + { + AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata(); + return GifMetadata.FromAnimatedMetadata(ani); + } + + return new(); + } + + private static GifFrameMetadata? GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) + where TPixel : unmanaged, IPixel + { + if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata? gif)) + { + return gif; + } + + GifFrameMetadata? metadata = null; + if (frame.Metadata.TryGetPngFrameMetadata(out PngFrameMetadata? png)) + { + AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); + metadata = GifFrameMetadata.FromAnimatedMetadata(ani); + } + + if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) + { + AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); + metadata = GifFrameMetadata.FromAnimatedMetadata(ani); + } + + if (metadata?.ColorTableMode == GifColorTableMode.Global && transparencyIndex > -1) + { + metadata.HasTransparency = true; + metadata.TransparencyIndex = unchecked((byte)transparencyIndex); + } + + return metadata; + } + private void EncodeAdditionalFrames( Stream stream, Image image, - ReadOnlyMemory globalPalette) + ReadOnlyMemory globalPalette, + int globalTransparencyIndex) where TPixel : unmanaged, IPixel { if (image.Frames.Count == 1) @@ -195,8 +250,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { // Gather the metadata for this frame. ImageFrame currentFrame = image.Frames[i]; - ImageFrameMetadata metadata = currentFrame.Metadata; - metadata.TryGetGifMetadata(out GifFrameMetadata? gifMetadata); + GifFrameMetadata? gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex); bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata?.ColorTableMode == GifColorTableMode.Local); if (!useLocal && !hasPaletteQuantizer && i > 0) diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs index faabf7dfa8..f8734bb5a3 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Gif; @@ -76,4 +77,43 @@ public class GifFrameMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new GifFrameMetadata(this); + + internal static GifFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) + { + // TODO: v4 How do I link the parent metadata to the frame metadata to get the global color table? + int index = -1; + float background = 1f; + if (metadata.ColorTable.HasValue) + { + ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; + for (int i = 0; i < colorTable.Length; i++) + { + Vector4 vector = (Vector4)colorTable[i]; + if (vector.W < background) + { + index = i; + } + } + } + + bool hasTransparency = index >= 0; + + return new() + { + LocalColorTable = metadata.ColorTable, + ColorTableMode = metadata.ColorTableMode == FrameColorTableMode.Global ? GifColorTableMode.Global : GifColorTableMode.Local, + FrameDelay = (int)Math.Round(metadata.Duration.TotalMilliseconds / 10), + DisposalMethod = GetMode(metadata.DisposalMode), + HasTransparency = hasTransparency, + TransparencyIndex = hasTransparency ? unchecked((byte)index) : byte.MinValue, + }; + } + + private static GifDisposalMethod GetMode(FrameDisposalMode mode) => mode switch + { + FrameDisposalMode.DoNotDispose => GifDisposalMethod.NotDispose, + FrameDisposalMode.RestoreToBackground => GifDisposalMethod.RestoreToBackground, + FrameDisposalMode.RestoreToPrevious => GifDisposalMethod.RestoreToPrevious, + _ => GifDisposalMethod.Unspecified, + }; } diff --git a/src/ImageSharp/Formats/Gif/GifMetadata.cs b/src/ImageSharp/Formats/Gif/GifMetadata.cs index d25e2a5cc2..1331edee89 100644 --- a/src/ImageSharp/Formats/Gif/GifMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifMetadata.cs @@ -71,4 +71,30 @@ public class GifMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new GifMetadata(this); + + internal static GifMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) + { + int index = 0; + Color background = metadata.BackgroundColor; + if (metadata.ColorTable.HasValue) + { + ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; + for (int i = 0; i < colorTable.Length; i++) + { + if (background == colorTable[i]) + { + index = i; + break; + } + } + } + + return new() + { + GlobalColorTable = metadata.ColorTable, + ColorTableMode = metadata.ColorTableMode == FrameColorTableMode.Global ? GifColorTableMode.Global : GifColorTableMode.Local, + RepeatCount = metadata.RepeatCount, + BackgroundColorIndex = (byte)Numerics.Clamp(index, 0, 255), + }; + } } diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 9ba95952e7..f4eaffe6b3 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Metadata; @@ -20,6 +21,21 @@ public static partial class MetadataExtensions public static GifMetadata GetGifMetadata(this ImageMetadata source) => source.GetFormatMetadata(GifFormat.Instance); + /// + /// Gets the gif format specific metadata for the image. + /// + /// The metadata this method extends. + /// + /// When this method returns, contains the metadata associated with the specified image, + /// if found; otherwise, the default value for the type of the metadata parameter. + /// This parameter is passed uninitialized. + /// + /// + /// if the gif metadata exists; otherwise, . + /// + public static bool TryGetGifMetadata(this ImageMetadata source, [NotNullWhen(true)] out GifMetadata? metadata) + => source.TryGetFormatMetadata(GifFormat.Instance, out metadata); + /// /// Gets the gif format specific metadata for the image frame. /// @@ -40,6 +56,32 @@ public static partial class MetadataExtensions /// /// if the gif frame metadata exists; otherwise, . /// - public static bool TryGetGifMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata) + public static bool TryGetGifFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata) => source.TryGetFormatMetadata(GifFormat.Instance, out metadata); + + internal static AnimatedImageMetadata ToAnimatedImageMetadata(this GifMetadata source) + => new() + { + ColorTable = source.GlobalColorTable, + ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, + RepeatCount = source.RepeatCount, + }; + + internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source) + => new() + { + ColorTable = source.LocalColorTable, + ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, + Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), + DisposalMode = GetMode(source.DisposalMethod), + BlendMode = FrameBlendMode.Source, + }; + + private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch + { + GifDisposalMethod.NotDispose => FrameDisposalMode.DoNotDispose, + GifDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, + GifDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, + _ => FrameDisposalMode.Unspecified, + }; } diff --git a/src/ImageSharp/Formats/Png/Chunks/AnimationControl.cs b/src/ImageSharp/Formats/Png/Chunks/AnimationControl.cs index a9f99a9e4a..cd78f80885 100644 --- a/src/ImageSharp/Formats/Png/Chunks/AnimationControl.cs +++ b/src/ImageSharp/Formats/Png/Chunks/AnimationControl.cs @@ -9,7 +9,7 @@ internal readonly struct AnimationControl { public const int Size = 8; - public AnimationControl(int numberFrames, int numberPlays) + public AnimationControl(uint numberFrames, uint numberPlays) { this.NumberFrames = numberFrames; this.NumberPlays = numberPlays; @@ -18,12 +18,12 @@ internal readonly struct AnimationControl /// /// Gets the number of frames /// - public int NumberFrames { get; } + public uint NumberFrames { get; } /// /// Gets the number of times to loop this APNG. 0 indicates infinite looping. /// - public int NumberPlays { get; } + public uint NumberPlays { get; } /// /// Writes the acTL to the given buffer. @@ -31,8 +31,8 @@ internal readonly struct AnimationControl /// The buffer to write to. public void WriteTo(Span buffer) { - BinaryPrimitives.WriteInt32BigEndian(buffer[..4], this.NumberFrames); - BinaryPrimitives.WriteInt32BigEndian(buffer[4..8], this.NumberPlays); + BinaryPrimitives.WriteInt32BigEndian(buffer[..4], (int)this.NumberFrames); + BinaryPrimitives.WriteInt32BigEndian(buffer[4..8], (int)this.NumberPlays); } /// @@ -42,6 +42,6 @@ internal readonly struct AnimationControl /// The parsed acTL. public static AnimationControl Parse(ReadOnlySpan data) => new( - numberFrames: BinaryPrimitives.ReadInt32BigEndian(data[..4]), - numberPlays: BinaryPrimitives.ReadInt32BigEndian(data[4..8])); + numberFrames: BinaryPrimitives.ReadUInt32BigEndian(data[..4]), + numberPlays: BinaryPrimitives.ReadUInt32BigEndian(data[4..8])); } diff --git a/src/ImageSharp/Formats/Png/MetadataExtensions.cs b/src/ImageSharp/Formats/Png/MetadataExtensions.cs index f24b8d1b5c..4a606d3a4a 100644 --- a/src/ImageSharp/Formats/Png/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Png/MetadataExtensions.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; @@ -20,17 +21,56 @@ public static partial class MetadataExtensions public static PngMetadata GetPngMetadata(this ImageMetadata source) => source.GetFormatMetadata(PngFormat.Instance); /// - /// Gets the aPng format specific metadata for the image frame. + /// Gets the png format specific metadata for the image. + /// + /// The metadata this method extends. + /// The metadata. + /// + /// if the png metadata exists; otherwise, . + /// + public static bool TryGetPngMetadata(this ImageMetadata source, [NotNullWhen(true)] out PngMetadata? metadata) + => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); + + /// + /// Gets the png format specific metadata for the image frame. /// /// The metadata this method extends. /// The . public static PngFrameMetadata GetPngFrameMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance); /// - /// Gets the aPng format specific metadata for the image frame. + /// Gets the png format specific metadata for the image frame. /// /// The metadata this method extends. /// The metadata. - /// The . - public static bool TryGetPngFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); + /// + /// if the png frame metadata exists; otherwise, . + /// + public static bool TryGetPngFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) + => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); + + internal static AnimatedImageMetadata ToAnimatedImageMetadata(this PngMetadata source) + => new() + { + ColorTable = source.ColorTable, + ColorTableMode = FrameColorTableMode.Global, + RepeatCount = (ushort)Numerics.Clamp(source.RepeatCount, 0, ushort.MaxValue), + }; + + internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this PngFrameMetadata source) + => new() + { + ColorTableMode = FrameColorTableMode.Global, + Duration = TimeSpan.FromMilliseconds(source.FrameDelay.ToDouble() * 1000), + DisposalMode = GetMode(source.DisposalMethod), + BlendMode = source.BlendMethod == PngBlendMethod.Source ? FrameBlendMode.Source : FrameBlendMode.Over, + }; + + private static FrameDisposalMode GetMode(PngDisposalMethod method) => method switch + { + PngDisposalMethod.None => FrameDisposalMode.DoNotDispose, + PngDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, + PngDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, + _ => FrameDisposalMode.Unspecified, + }; } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d8305a3f57..7d573efb62 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -621,8 +621,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. - if (previousFrameControl.DisposeOperation == PngDisposalMethod.Background - || (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.Previous)) + if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground + || (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) { Rectangle restoreArea = previousFrameControl.Bounds; Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea); diff --git a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs b/src/ImageSharp/Formats/Png/PngDisposalMethod.cs index 17391de95c..a431e8941f 100644 --- a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs +++ b/src/ImageSharp/Formats/Png/PngDisposalMethod.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats.Png; @@ -16,10 +16,10 @@ public enum PngDisposalMethod /// /// The frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame. /// - Background, + RestoreToBackground, /// /// The frame's region of the output buffer is to be reverted to the previous contents before rendering the next frame. /// - Previous + RestoreToPrevious } diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 04e3b1d840..be6991bab1 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -176,7 +176,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { - this.WriteAnimationControlChunk(stream, image.Frames.Count, pngMetadata.RepeatCount); + this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); // TODO: We should attempt to optimize the output by clipping the indexed result to // non-transparent bounds. That way we can assign frame control bounds and encode @@ -621,7 +621,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// The containing image data. /// The number of frames. /// The number of times to loop this APNG. - private void WriteAnimationControlChunk(Stream stream, int framesCount, int playsCount) + private void WriteAnimationControlChunk(Stream stream, uint framesCount, uint playsCount) { AnimationControl acTL = new(framesCount, playsCount); diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index b113dbfc17..6110cdd0c7 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Png.Chunks; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Png; @@ -82,7 +81,7 @@ public class PngMetadata : IDeepCloneable /// /// Gets or sets the number of times to loop this APNG. 0 indicates infinite looping. /// - public int RepeatCount { get; set; } + public uint RepeatCount { get; set; } /// public IDeepCloneable DeepClone() => new PngMetadata(this); diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index d502fd6063..49b059b078 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -160,7 +160,7 @@ internal abstract class BitWriterBase /// The number of times to loop the animation. If it is 0, this means infinitely. public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount) { - WebpAnimationParameter chunk = new(background.ToRgba32().Rgba, loopCount); + WebpAnimationParameter chunk = new(background.ToBgra32().PackedValue, loopCount); chunk.WriteTo(stream); } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index f22a3fd540..aee5183264 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -32,8 +32,8 @@ internal readonly struct WebpFrameData width, height, duration, - (flags & 2) != 0 ? WebpBlendingMethod.DoNotBlend : WebpBlendingMethod.AlphaBlending, - (flags & 1) == 1 ? WebpDisposalMethod.Dispose : WebpDisposalMethod.DoNotDispose) + (flags & 2) == 0 ? WebpBlendingMethod.Over : WebpBlendingMethod.Source, + (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.None) { } @@ -93,13 +93,13 @@ internal readonly struct WebpFrameData { byte flags = 0; - if (this.BlendingMethod is WebpBlendingMethod.DoNotBlend) + if (this.BlendingMethod is WebpBlendingMethod.Source) { // Set blending flag. flags |= 2; } - if (this.DisposalMethod is WebpDisposalMethod.Dispose) + if (this.DisposalMethod is WebpDisposalMethod.RestoreToBackground) { // Set disposal flag. flags |= 1; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 4fdbb31d37..0821be5777 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -260,7 +260,7 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { WebpMetadata webpMetadata = metadata.GetWebpMetadata(); - BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount); + BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } } diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 98e50bb9c2..3fea72c07e 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -334,7 +334,7 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { WebpMetadata webpMetadata = metadata.GetWebpMetadata(); - BitWriterBase.WriteAnimationParameter(stream, webpMetadata.AnimationBackground, webpMetadata.AnimationLoopCount); + BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } } diff --git a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs index 7f0920f2dd..44da191d2d 100644 --- a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; @@ -18,10 +20,56 @@ public static partial class MetadataExtensions /// The . public static WebpMetadata GetWebpMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance); + /// + /// Gets the webp format specific metadata for the image. + /// + /// The metadata this method extends. + /// The metadata. + /// + /// if the webp metadata exists; otherwise, . + /// + public static bool TryGetWebpMetadata(this ImageMetadata source, [NotNullWhen(true)] out WebpMetadata? metadata) + => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata); + /// /// Gets the webp format specific metadata for the image frame. /// /// The metadata this method extends. /// The . public static WebpFrameMetadata GetWebpMetadata(this ImageFrameMetadata metadata) => metadata.GetFormatMetadata(WebpFormat.Instance); + + /// + /// Gets the webp format specific metadata for the image frame. + /// + /// The metadata this method extends. + /// The metadata. + /// + /// if the webp frame metadata exists; otherwise, . + /// + public static bool TryGetWebpFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out WebpFrameMetadata? metadata) + => source.TryGetFormatMetadata(WebpFormat.Instance, out metadata); + + internal static AnimatedImageMetadata ToAnimatedImageMetadata(this WebpMetadata source) + => new() + { + ColorTableMode = FrameColorTableMode.Global, + RepeatCount = source.RepeatCount, + BackgroundColor = source.BackgroundColor + }; + + internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this WebpFrameMetadata source) + => new() + { + ColorTableMode = FrameColorTableMode.Global, + Duration = TimeSpan.FromMilliseconds(source.FrameDelay), + DisposalMode = GetMode(source.DisposalMethod), + BlendMode = source.BlendMethod == WebpBlendingMethod.Over ? FrameBlendMode.Over : FrameBlendMode.Source, + }; + + private static FrameDisposalMode GetMode(WebpDisposalMethod method) => method switch + { + WebpDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, + WebpDisposalMethod.None => FrameDisposalMode.DoNotDispose, + _ => FrameDisposalMode.DoNotDispose, + }; } diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 66e69d9a43..f081cfcd89 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -89,7 +89,7 @@ internal class WebpAnimationDecoder : IDisposable this.metadata = new ImageMetadata(); this.webpMetadata = this.metadata.GetWebpMetadata(); - this.webpMetadata.AnimationLoopCount = features.AnimationLoopCount; + this.webpMetadata.RepeatCount = features.AnimationLoopCount; Span buffer = stackalloc byte[4]; uint frameCount = 0; @@ -195,14 +195,14 @@ internal class WebpAnimationDecoder : IDisposable Rectangle regionRectangle = frameData.Bounds; - if (frameData.DisposalMethod is WebpDisposalMethod.Dispose) + if (frameData.DisposalMethod is WebpDisposalMethod.RestoreToBackground) { this.RestoreToBackground(imageFrame, backgroundColor); } using Buffer2D decodedImageFrame = this.DecodeImageFrameData(frameData, webpInfo); - bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendingMethod.AlphaBlending; + bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendingMethod.Over; DrawDecodedImageFrameOnCanvas(decodedImageFrame, imageFrame, regionRectangle, blend); previousFrame = currentFrame ?? image.Frames.RootFrame; diff --git a/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs index cbd0e9a8cc..482d62cd23 100644 --- a/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs @@ -9,14 +9,14 @@ namespace SixLabors.ImageSharp.Formats.Webp; public enum WebpBlendingMethod { /// - /// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending. - /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle. + /// Do not blend. After disposing of the previous frame, + /// render the current frame on the canvas by overwriting the rectangle covered by the current frame. /// - AlphaBlending = 0, + Source = 0, /// - /// Do not blend. After disposing of the previous frame, - /// render the current frame on the canvas by overwriting the rectangle covered by the current frame. + /// Use alpha blending. After disposing of the previous frame, render the current frame on the canvas using alpha-blending. + /// If the current frame does not have an alpha channel, assume alpha value of 255, effectively replacing the rectangle. /// - DoNotBlend = 1 + Over = 1, } diff --git a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs index d409973a99..397c2ee502 100644 --- a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs @@ -11,10 +11,10 @@ public enum WebpDisposalMethod /// /// Do not dispose. Leave the canvas as is. /// - DoNotDispose = 0, + None = 0, /// /// Dispose to background color. Fill the rectangle on the canvas covered by the current frame with background color specified in the ANIM chunk. /// - Dispose = 1 + RestoreToBackground = 1 } diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs index a6bb0a7b80..9d0d8d08d2 100644 --- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs @@ -22,8 +22,8 @@ public class WebpMetadata : IDeepCloneable private WebpMetadata(WebpMetadata other) { this.FileFormat = other.FileFormat; - this.AnimationLoopCount = other.AnimationLoopCount; - this.AnimationBackground = other.AnimationBackground; + this.RepeatCount = other.RepeatCount; + this.BackgroundColor = other.BackgroundColor; } /// @@ -34,15 +34,15 @@ public class WebpMetadata : IDeepCloneable /// /// Gets or sets the loop count. The number of times to loop the animation. 0 means infinitely. /// - public ushort AnimationLoopCount { get; set; } = 1; + public ushort RepeatCount { get; set; } = 1; /// - /// Gets or sets the default background color of the canvas in [Blue, Green, Red, Alpha] byte order. - /// This color MAY be used to fill the unused space on the canvas around the frames, + /// Gets or sets the default background color of the canvas when animating. + /// This color may be used to fill the unused space on the canvas around the frames, /// as well as the transparent pixels of the first frame. - /// The background color is also used when the Disposal method is 1. + /// The background color is also used when the Disposal method is . /// - public Color AnimationBackground { get; set; } + public Color BackgroundColor { get; set; } /// public IDeepCloneable DeepClone() => new WebpMetadata(this); diff --git a/src/ImageSharp/Metadata/FrameDecodingMode.cs b/src/ImageSharp/Metadata/FrameDecodingMode.cs deleted file mode 100644 index 3a59654897..0000000000 --- a/src/ImageSharp/Metadata/FrameDecodingMode.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Metadata; - -/// -/// Enumerated frame process modes to apply to multi-frame images. -/// -public enum FrameDecodingMode -{ - /// - /// Decodes all the frames of a multi-frame image. - /// - All, - - /// - /// Decodes only the first frame of a multi-frame image. - /// - First -} diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index f54fc5c7ae..e1284b50e8 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -183,6 +183,32 @@ public sealed class ImageMetadata : IDeepCloneable return newMeta; } + /// + /// Gets the metadata value associated with the specified key. + /// + /// The type of format metadata. + /// The key of the value to get. + /// + /// When this method returns, contains the metadata associated with the specified key, + /// if the key is found; otherwise, the default value for the type of the metadata parameter. + /// This parameter is passed uninitialized. + /// + /// + /// if the frame metadata exists for the specified key; otherwise, . + /// + public bool TryGetFormatMetadata(IImageFormat key, out TFormatMetadata? metadata) + where TFormatMetadata : class, IDeepCloneable + { + if (this.formatMetadata.TryGetValue(key, out IDeepCloneable? meta)) + { + metadata = (TFormatMetadata)meta; + return true; + } + + metadata = default; + return false; + } + /// public ImageMetadata DeepClone() => new(this); diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 31001e31b4..65d186c914 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -245,7 +245,7 @@ public class GifEncoderTests int count = 0; foreach (ImageFrame frame in image.Frames) { - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) + if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata _)) { count++; } @@ -261,7 +261,7 @@ public class GifEncoderTests count = 0; foreach (ImageFrame frame in image2.Frames) { - if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) + if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata _)) { count++; } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 92c07a27a6..a6840b33e4 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -3,6 +3,7 @@ // ReSharper disable InconsistentNaming using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -453,6 +454,10 @@ public partial class PngEncoderTests memStream.Position = 0; image.DebugSave(provider: provider, encoder: PngEncoder, null, false); + image.DebugSave(provider: provider, encoder: new GifEncoder(), "gif", false); + + string path = provider.Utility.GetTestOutputFileName("gif"); + image.Save(path); using Image output = Image.Load(memStream); ImageComparer.Exact.VerifySimilarity(output, image); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngFrameMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngFrameMetadataTests.cs index e29585c2dc..9ba2617281 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngFrameMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngFrameMetadataTests.cs @@ -14,7 +14,7 @@ public class PngFrameMetadataTests PngFrameMetadata meta = new() { FrameDelay = new(1, 0), - DisposalMethod = PngDisposalMethod.Background, + DisposalMethod = PngDisposalMethod.RestoreToBackground, BlendMethod = PngBlendMethod.Over, }; @@ -25,7 +25,7 @@ public class PngFrameMetadataTests Assert.True(meta.BlendMethod.Equals(clone.BlendMethod)); clone.FrameDelay = new(2, 1); - clone.DisposalMethod = PngDisposalMethod.Previous; + clone.DisposalMethod = PngDisposalMethod.RestoreToPrevious; clone.BlendMethod = PngBlendMethod.Source; Assert.False(meta.FrameDelay.Equals(clone.FrameDelay)); diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 4b03671e16..6301f341cc 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -307,7 +307,7 @@ public class WebpDecoderTests image.DebugSaveMultiFrame(provider); image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact); - Assert.Equal(0, webpMetaData.AnimationLoopCount); + Assert.Equal(0, webpMetaData.RepeatCount); Assert.Equal(150U, frameMetaData.FrameDelay); Assert.Equal(12, image.Frames.Count); } @@ -324,7 +324,7 @@ public class WebpDecoderTests image.DebugSaveMultiFrame(provider); image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Tolerant(0.04f)); - Assert.Equal(0, webpMetaData.AnimationLoopCount); + Assert.Equal(0, webpMetaData.RepeatCount); Assert.Equal(150U, frameMetaData.FrameDelay); Assert.Equal(12, image.Frames.Count); } From 8d7ac6ea5a99fbd3b45bccab62c34f8095414222 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 16 Nov 2023 13:37:05 +1000 Subject: [PATCH 030/219] Fix boxed quantization and update refs --- .../Quantization/OctreeQuantizer{TPixel}.cs | 10 ++-- .../Quantization/QuantizeProcessor{TPixel}.cs | 12 ++-- .../Quantization/QuantizerUtilities.cs | 10 ++-- .../Quantization/WuQuantizer{TPixel}.cs | 20 +++---- .../Processors/Quantization/QuantizerTests.cs | 55 ++++++------------- ...InBox_Bike_OctreeQuantizer_ErrorDither.png | 4 +- ...ionInBox_Bike_OctreeQuantizer_NoDither.png | 4 +- ...Box_Bike_OctreeQuantizer_OrderedDither.png | 4 +- ...ke_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ..._Bike_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ike_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...x_Bike_WernerPaletteQuantizer_NoDither.png | 4 +- ...e_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...tionInBox_Bike_WuQuantizer_ErrorDither.png | 4 +- ...izationInBox_Bike_WuQuantizer_NoDither.png | 4 +- ...onInBox_Bike_WuQuantizer_OrderedDither.png | 4 +- ...oraPartial_OctreeQuantizer_ErrorDither.png | 4 +- ...iphoraPartial_OctreeQuantizer_NoDither.png | 4 +- ...aPartial_OctreeQuantizer_OrderedDither.png | 4 +- ...al_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ...rtial_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ial_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...artial_WernerPaletteQuantizer_NoDither.png | 4 +- ...l_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...liphoraPartial_WuQuantizer_ErrorDither.png | 4 +- ...CalliphoraPartial_WuQuantizer_NoDither.png | 4 +- ...phoraPartial_WuQuantizer_OrderedDither.png | 4 +- 29 files changed, 89 insertions(+), 114 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index 1136fbc9da..fe422882bc 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -60,7 +60,7 @@ public struct OctreeQuantizer : IQuantizer public QuantizerOptions Options { get; } /// - public ReadOnlyMemory Palette + public readonly ReadOnlyMemory Palette { get { @@ -72,16 +72,14 @@ public struct OctreeQuantizer : IQuantizer /// public void AddPaletteColors(Buffer2DRegion pixelRegion) { - Rectangle bounds = pixelRegion.Rectangle; - Buffer2D source = pixelRegion.Buffer; - using (IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(bounds.Width)) + using (IMemoryOwner buffer = this.Configuration.MemoryAllocator.Allocate(pixelRegion.Width)) { Span bufferSpan = buffer.GetSpan(); // Loop through each row - for (int y = bounds.Top; y < bounds.Bottom; y++) + for (int y = 0; y < pixelRegion.Height; y++) { - Span row = source.DangerousGetRowSpan(y).Slice(bounds.Left, bounds.Width); + Span row = pixelRegion.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgba32(this.Configuration, row, bufferSpan); for (int x = 0; x < bufferSpan.Length; x++) diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs index f8be91bc2b..da2580fedf 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizeProcessor{TPixel}.cs @@ -32,7 +32,7 @@ internal class QuantizeProcessor : ImageProcessor /// protected override void OnFrameApply(ImageFrame source) { - var interest = Rectangle.Intersect(source.Bounds(), this.SourceRectangle); + Rectangle interest = Rectangle.Intersect(source.Bounds(), this.SourceRectangle); Configuration configuration = this.Configuration; using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(configuration); @@ -43,14 +43,14 @@ internal class QuantizeProcessor : ImageProcessor int offsetX = interest.Left; Buffer2D sourceBuffer = source.PixelBuffer; - for (int y = interest.Y; y < interest.Height; y++) + for (int y = 0; y < quantized.Height; y++) { - Span row = sourceBuffer.DangerousGetRowSpan(y); - ReadOnlySpan quantizedRow = quantized.DangerousGetRowSpan(y - offsetY); + ReadOnlySpan quantizedRow = quantized.DangerousGetRowSpan(y); + Span row = sourceBuffer.DangerousGetRowSpan(y + offsetY); - for (int x = interest.Left; x < interest.Right; x++) + for (int x = 0; x < quantized.Width; x++) { - row[x] = paletteSpan[quantizedRow[x - offsetX]]; + row[x + offsetX] = paletteSpan[quantizedRow[x]]; } } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index 53203f94a0..a7edec662e 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -154,14 +154,14 @@ public static class QuantizerUtilities int offsetY = bounds.Top; int offsetX = bounds.Left; - for (int y = bounds.Y; y < bounds.Height; y++) + for (int y = 0; y < destination.Height; y++) { - Span sourceRow = sourceBuffer.DangerousGetRowSpan(y); - Span destinationRow = destination.GetWritablePixelRowSpanUnsafe(y - offsetY); + Span sourceRow = sourceBuffer.DangerousGetRowSpan(y + offsetY); + Span destinationRow = destination.GetWritablePixelRowSpanUnsafe(y); - for (int x = bounds.Left; x < bounds.Right; x++) + for (int x = 0; x < destination.Width; x++) { - destinationRow[x - offsetX] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); + destinationRow[x] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 524153804c..f6928c3dd4 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -123,10 +123,11 @@ internal struct WuQuantizer : IQuantizer /// public void AddPaletteColors(Buffer2DRegion pixelRegion) { - Rectangle bounds = pixelRegion.Rectangle; - Buffer2D source = pixelRegion.Buffer; - - this.Build3DHistogram(source, bounds); + // TODO: Something is destroying the existing palette when adding new colors. + // When the QuantizingImageEncoder.PixelSamplingStrategy is DefaultPixelSamplingStrategy + // this leads to performance issues + the palette is not preserved. + // https://github.com/SixLabors/ImageSharp/issues/2498 + this.Build3DHistogram(pixelRegion); this.Get3DMoments(this.memoryAllocator); this.BuildCube(); @@ -360,19 +361,18 @@ internal struct WuQuantizer : IQuantizer /// /// Builds a 3-D color histogram of counts, r/g/b, c^2. /// - /// The source data. - /// The bounds within the source image to quantize. - private readonly void Build3DHistogram(Buffer2D source, Rectangle bounds) + /// The source pixel data. + private readonly void Build3DHistogram(Buffer2DRegion source) { Span momentSpan = this.momentsOwner.GetSpan(); // Build up the 3-D color histogram - using IMemoryOwner buffer = this.memoryAllocator.Allocate(bounds.Width); + using IMemoryOwner buffer = this.memoryAllocator.Allocate(source.Width); Span bufferSpan = buffer.GetSpan(); - for (int y = bounds.Top; y < bounds.Bottom; y++) + for (int y = 0; y < source.Height; y++) { - Span row = source.DangerousGetRowSpan(y).Slice(bounds.Left, bounds.Width); + Span row = source.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgba32(this.Configuration, row, bufferSpan); for (int x = 0; x < bufferSpan.Length; x++) diff --git a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs index d26032c7ef..b8b4615b94 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Quantization/QuantizerTests.cs @@ -12,74 +12,66 @@ namespace SixLabors.ImageSharp.Tests.Processing.Processors.Quantization; [Trait("Category", "Processors")] public class QuantizerTests { - /// - /// Something is causing tests to fail on NETFX in CI. - /// Could be a JIT error as everything runs well and is identical to .NET Core output. - /// Not worth investigating for now. - /// - /// - private static readonly bool SkipAllQuantizerTests = TestEnvironment.IsFramework; - public static readonly string[] CommonTestImages = { TestImages.Png.CalliphoraPartial, TestImages.Png.Bike }; - private static readonly QuantizerOptions NoDitherOptions = new QuantizerOptions { Dither = null }; - private static readonly QuantizerOptions DiffuserDitherOptions = new QuantizerOptions { Dither = KnownDitherings.FloydSteinberg }; - private static readonly QuantizerOptions OrderedDitherOptions = new QuantizerOptions { Dither = KnownDitherings.Bayer8x8 }; + private static readonly QuantizerOptions NoDitherOptions = new() { Dither = null }; + private static readonly QuantizerOptions DiffuserDitherOptions = new() { Dither = KnownDitherings.FloydSteinberg }; + private static readonly QuantizerOptions OrderedDitherOptions = new() { Dither = KnownDitherings.Bayer8x8 }; - private static readonly QuantizerOptions Diffuser0_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Diffuser0_ScaleDitherOptions = new() { Dither = KnownDitherings.FloydSteinberg, DitherScale = 0F }; - private static readonly QuantizerOptions Diffuser0_25_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Diffuser0_25_ScaleDitherOptions = new() { Dither = KnownDitherings.FloydSteinberg, DitherScale = .25F }; - private static readonly QuantizerOptions Diffuser0_5_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Diffuser0_5_ScaleDitherOptions = new() { Dither = KnownDitherings.FloydSteinberg, DitherScale = .5F }; - private static readonly QuantizerOptions Diffuser0_75_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Diffuser0_75_ScaleDitherOptions = new() { Dither = KnownDitherings.FloydSteinberg, DitherScale = .75F }; - private static readonly QuantizerOptions Ordered0_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Ordered0_ScaleDitherOptions = new() { Dither = KnownDitherings.Bayer8x8, DitherScale = 0F }; - private static readonly QuantizerOptions Ordered0_25_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Ordered0_25_ScaleDitherOptions = new() { Dither = KnownDitherings.Bayer8x8, DitherScale = .25F }; - private static readonly QuantizerOptions Ordered0_5_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Ordered0_5_ScaleDitherOptions = new() { Dither = KnownDitherings.Bayer8x8, DitherScale = .5F }; - private static readonly QuantizerOptions Ordered0_75_ScaleDitherOptions = new QuantizerOptions + private static readonly QuantizerOptions Ordered0_75_ScaleDitherOptions = new() { Dither = KnownDitherings.Bayer8x8, DitherScale = .75F }; public static readonly TheoryData Quantizers - = new TheoryData + = new() { // Known uses error diffusion by default. KnownQuantizers.Octree, @@ -97,7 +89,7 @@ public class QuantizerTests }; public static readonly TheoryData DitherScaleQuantizers - = new TheoryData + = new() { new OctreeQuantizer(Diffuser0_ScaleDitherOptions), new WebSafePaletteQuantizer(Diffuser0_ScaleDitherOptions), @@ -151,7 +143,7 @@ public class QuantizerTests }; public static readonly TheoryData DefaultInstanceDitherers - = new TheoryData + = new() { default(ErrorDither), default(OrderedDither) @@ -164,11 +156,6 @@ public class QuantizerTests public void ApplyQuantizationInBox(TestImageProvider provider, IQuantizer quantizer) where TPixel : unmanaged, IPixel { - if (SkipAllQuantizerTests) - { - return; - } - string quantizerName = quantizer.GetType().Name; string ditherName = quantizer.Options.Dither?.GetType()?.Name ?? "NoDither"; string testOutputDetails = $"{quantizerName}_{ditherName}"; @@ -185,11 +172,6 @@ public class QuantizerTests public void ApplyQuantization(TestImageProvider provider, IQuantizer quantizer) where TPixel : unmanaged, IPixel { - if (SkipAllQuantizerTests) - { - return; - } - string quantizerName = quantizer.GetType().Name; string ditherName = quantizer.Options.Dither?.GetType()?.Name ?? "NoDither"; string testOutputDetails = $"{quantizerName}_{ditherName}"; @@ -206,11 +188,6 @@ public class QuantizerTests public void ApplyQuantizationWithDitheringScale(TestImageProvider provider, IQuantizer quantizer) where TPixel : unmanaged, IPixel { - if (SkipAllQuantizerTests) - { - return; - } - string quantizerName = quantizer.GetType().Name; string ditherName = quantizer.Options.Dither.GetType().Name; float ditherScale = quantizer.Options.DitherScale; @@ -229,8 +206,8 @@ public class QuantizerTests { void Command() { - using var image = new Image(10, 10); - var quantizer = new WebSafePaletteQuantizer(); + using Image image = new(10, 10); + WebSafePaletteQuantizer quantizer = new(); quantizer.Options.Dither = dither; image.Mutate(x => x.Quantize(quantizer)); } diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png index 4011bbc38e..a7730d4e65 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df15b095693880ec25f4fda378c8404a55064d83a40fc889f4e7ebb251dd88cf -size 272529 +oid sha256:f4d36c8f7e5d5c0d798af5fb6bfad28ed0d628b880bea81efe0d54ac1fde86b2 +size 265268 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png index 0c53f8d42d..d993923d48 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd18f2ba17869695efda6acf7daa0f4def11a4f5ba6cee95e06cee505f076c77 -size 263994 +oid sha256:9f165908729d723818b6c5843bd75298d987448e2cd4278dfe3f388a62025add +size 238396 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png index ff1e888096..223d3bc012 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7bcd315c4f140b55b294216de83f7835dcdf027acbd9cdb5e8bcbd89360c4781 -size 272971 +oid sha256:34eaa0696da00838e591b2c48e7797641521f7f3feb01abbd774591c4dd6f200 +size 265546 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png index 081e6dbdfe..367db5ea10 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fb9b649fd0b217ce548d46b0e7958f5ab74b5862678d34839d7b7ab29e3722ee -size 255871 +oid sha256:531594a2e47710545d96d0fd9a8cc86983233420172e0ced28df050df1a5e039 +size 239844 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png index c0186e4272..922c2bf9b2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c0374d786d726692e83022a5d8642807ad24f9d484393d564a4cc73a3f8971f8 -size 250230 +oid sha256:4f1462733e02d499b0d8c61ab835a27c7fee560fdc7fc521d20ec09bb4ccc80f +size 216030 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png index 05f9404ed1..29c93d14e2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8a9f1fab68b71ae87b7f8f8fa61cd73c6e868359bff60e91c1246eb04c92740 -size 252981 +oid sha256:7e6d91a3ec4f974af675dc360fd5fd623ec8773cdbc88c0a3a6506880838718a +size 226727 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png index 1eeabc6664..f8b5e61332 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:216d096da3a1e5df9cffa1dddc2c136c4ad0db1ca3ff930a46193352680e91d6 -size 257442 +oid sha256:620463c14de12abb4f2cab3ee6259ad8cbb24c688212729535f41ebf492a8836 +size 224490 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png index afa308a920..dbfab2b508 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8c15a5b6114825ff1f118209831a89d8619ea2c956ad52f9564dfc41be94c6cb -size 255797 +oid sha256:c68eba122814b5470e5f2e03e34190ff79e84e4b431ad8227355ce7ffcd4a6a7 +size 220192 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png index 2d61083331..86655af42b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9694b6b29e33c5b0b5a8f662246f5ad0af03b900d52615fa61cad6d16cebb31c -size 259740 +oid sha256:6dbd3189b559941f91dd6e0aa15b34a3e5081477400678c2396c6a66d398876f +size 230883 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png index 82c6b3ed58..a9e5e18dfa 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc776a1039f25212cbe983ae41de4bc3d8e53dd3f692c327da42d91fe983fe5d -size 275846 +oid sha256:274c3e57f186c47bb070dfd2a79b8353032f9d91d03a3ab9ecb3aec13fdd9855 +size 273333 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png index 5ea0460c1c..d8a1178adc 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8aced00a35f19ccb7011cc7ef04bcbe79b064078a5b7b1649ecab789da13160e -size 273774 +oid sha256:df63a3d12e2998d5242b64169ac86e3df7ab4be585a80daddc3e3888dfcb7095 +size 262298 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png index d96ad1e233..76946ee06f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4fe9d03e33808cf97e6ee3a4a877160b04746e46a3e3c56c0cdf7ab617e90d9 -size 276397 +oid sha256:457a0b4e27a09440ff4e13792b68fb5a9da82b7ce6129ea15a5ea8dcd99bd522 +size 274300 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png index 0e1781b119..b5cb6c0fa8 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2358c7b0c3de1f13d9d7840108ffd1b65751946ba28a697d6ae48b7445541807 -size 308226 +oid sha256:fd007786164af8f410bd9738c0a072fc75d1f9b50145e5c191c9e3df345341a5 +size 318778 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png index 5c58149639..7e3080562c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38c112f9edef86df31b8ccec63bffdd3d4426eb5fd44b774bef4166c70f31a90 -size 303086 +oid sha256:0203ecb9e4665e7c3992b7da4777c6d35b539790506fc9ca2acbcbc2bdb5db18 +size 303979 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png index 1b7ed02df8..5626fa1b83 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93fd2a28153ec292c0d6b2651830566fa3ee0cdcad7f6978ff8b49cd7fb2ac27 -size 308104 +oid sha256:62cdce27fc46a38a16995df8ed1501f65091d69315288479b1d613b1d87c8239 +size 321123 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png index a4d2d92a53..3ae9d369d6 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:faf061e22dd0e34c62929e9e742c279f400293b87fca15e2e6423115b3e02862 -size 290244 +oid sha256:08ace2edc5089a7742c1c8005126dcce850b1adf9c017b12db6892f4daeef1bb +size 271721 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png index bb973a0000..0205626738 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9a368ff9fbb4d462a99b9eaab8e2ec81e4b1ae1d120cf5abc0cc5fe02ea941c -size 285759 +oid sha256:3a2aae04edebcaca9b95f30963201794887fa0eac954b64c68bfe529b14fa9be +size 269397 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png index 83ae37b086..68d91fc437 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1926eec3a84dd8601ce0de5d8b1b70d25ebd120f4b9877b33266c18404a051fe -size 286469 +oid sha256:2f3e9a338a5ae37c88ce0c348e0b655429220da051db3352779c277bb2dcb441 +size 270622 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png index d3ca7f8c1c..11939c16cd 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2c45b7993e7019efae493f738d6fd441446d9ff5fdf14200003a1a8a90d67b97 -size 292334 +oid sha256:6ac7cdcc2fbee0572a369bed29c51e1c9056a4f09c4e0750ecb34d65daf403d4 +size 287741 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png index 37181fd36d..324bd92539 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:94edf1b16733a2632406f70b61bcb4f95bc9044706f63b1840cede693330814d -size 291415 +oid sha256:752760327cc1416c171a920f1e0e95e34eae6d78bd0c7393a3be427bf3c8e55c +size 284481 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png index 827fc0a694..52bf2a163f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:93ac2cc58c94e036287e76cda3970f070d15c4ded5dc2e553177772d327d56f6 -size 292742 +oid sha256:293459538454e07bc9ea1e9df1fa5b0eb986fde7de42f6c25b43e4c8859bd28a +size 285370 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png index 6164b3ed6b..9702a635d8 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:307cd34267e96ca51d82873138e319830d13743c2085788ffcdec9bf60d45671 -size 310380 +oid sha256:be7812accadc6347d6df43c308f7293596f92d0d90cf0b6a8e48fac1f4144fc0 +size 320157 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png index 4981078c40..d94d57759f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a8c296a49104edbd0ccb237c0333d3ab403e8ad5cc15c91f1734d2c3d78cf135 -size 309488 +oid sha256:ff094e6bafe81e818bcbac69018dcfe29366389dfca0d63d8e05ef42896ffe1d +size 317309 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png index f392f00d91..e016e3de69 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1874dab1b45fd976751395e1e9336ffb4d58e2e3d1643f48beea42f39245c98e -size 311280 +oid sha256:ee0778aac671365dd0afae06cdcf8f36243bd9815f684b975f83e297bb694e63 +size 323979 From a486558ed19a8fda1c60bf50e9e2e5d258b8bcbd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Nov 2023 13:19:02 +1000 Subject: [PATCH 031/219] Complete Webp and add tests --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 20 +++- .../Formats/Gif/MetadataExtensions.cs | 13 ++- .../Formats/Png/MetadataExtensions.cs | 18 ++- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 +- .../Formats/Png/PngDisposalMethod.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 59 +++++++++- .../Formats/Png/PngFrameMetadata.cs | 18 ++- src/ImageSharp/Formats/Png/PngMetadata.cs | 33 ++++++ .../Formats/Webp/Chunks/WebpFrameData.cs | 2 +- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 4 +- .../Formats/Webp/Lossy/Vp8Encoder.cs | 4 +- .../Formats/Webp/MetadataExtensions.cs | 2 +- .../Formats/Webp/WebpCommonUtils.cs | 56 ++++++++- .../Formats/Webp/WebpDisposalMethod.cs | 2 +- .../Formats/Webp/WebpEncoderCore.cs | 2 +- .../Formats/Webp/WebpFrameMetadata.cs | 8 ++ src/ImageSharp/Formats/Webp/WebpMetadata.cs | 8 ++ .../Quantization/EuclideanPixelMap{TPixel}.cs | 6 +- .../Formats/Gif/GifEncoderTests.cs | 92 ++++++++++++++- .../Formats/Png/PngEncoderTests.cs | 109 +++++++++++++++++- .../Formats/WebP/WebpEncoderTests.cs | 93 +++++++++++++++ 21 files changed, 515 insertions(+), 40 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 33942ce547..d22b960ec6 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -190,19 +190,20 @@ internal sealed class GifEncoderCore : IImageEncoderInternals return GifMetadata.FromAnimatedMetadata(ani); } + // Return explicit new instance so we do not mutate the original metadata. return new(); } private static GifFrameMetadata? GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) where TPixel : unmanaged, IPixel { - if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata? gif)) + if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) { return gif; } GifFrameMetadata? metadata = null; - if (frame.Metadata.TryGetPngFrameMetadata(out PngFrameMetadata? png)) + if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) { AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); metadata = GifFrameMetadata.FromAnimatedMetadata(ani); @@ -342,7 +343,20 @@ internal sealed class GifEncoderCore : IImageEncoderInternals } } - this.DeDuplicatePixels(previousFrame, currentFrame, encodingFrame, replacement); + // We can't deduplicate here as we need the background pixels to be present in the buffer. + if (metadata?.DisposalMethod == GifDisposalMethod.RestoreToBackground) + { + for (int y = 0; y < currentFrame.PixelBuffer.Height; y++) + { + Span sourceRow = currentFrame.PixelBuffer.DangerousGetRowSpan(y); + Span destinationRow = encodingFrame.PixelBuffer.DangerousGetRowSpan(y); + sourceRow.CopyTo(destinationRow); + } + } + else + { + this.DeDuplicatePixels(previousFrame, currentFrame, encodingFrame, replacement); + } IndexedImageFrame quantized; if (useLocal) diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index f4eaffe6b3..c7f9f84c80 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -56,16 +56,25 @@ public static partial class MetadataExtensions /// /// if the gif frame metadata exists; otherwise, . /// - public static bool TryGetGifFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata) + public static bool TryGetGifMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out GifFrameMetadata? metadata) => source.TryGetFormatMetadata(GifFormat.Instance, out metadata); internal static AnimatedImageMetadata ToAnimatedImageMetadata(this GifMetadata source) - => new() + { + Color background = Color.Transparent; + if (source.GlobalColorTable != null) + { + background = source.GlobalColorTable.Value.Span[source.BackgroundColorIndex]; + } + + return new() { ColorTable = source.GlobalColorTable, ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, RepeatCount = source.RepeatCount, + BackgroundColor = background, }; + } internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source) => new() diff --git a/src/ImageSharp/Formats/Png/MetadataExtensions.cs b/src/ImageSharp/Formats/Png/MetadataExtensions.cs index 4a606d3a4a..b6313bffe0 100644 --- a/src/ImageSharp/Formats/Png/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Png/MetadataExtensions.cs @@ -36,7 +36,7 @@ public static partial class MetadataExtensions /// /// The metadata this method extends. /// The . - public static PngFrameMetadata GetPngFrameMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance); + public static PngFrameMetadata GetPngMetadata(this ImageFrameMetadata source) => source.GetFormatMetadata(PngFormat.Instance); /// /// Gets the png format specific metadata for the image frame. @@ -46,7 +46,7 @@ public static partial class MetadataExtensions /// /// if the png frame metadata exists; otherwise, . /// - public static bool TryGetPngFrameMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) + public static bool TryGetPngMetadata(this ImageFrameMetadata source, [NotNullWhen(true)] out PngFrameMetadata? metadata) => source.TryGetFormatMetadata(PngFormat.Instance, out metadata); internal static AnimatedImageMetadata ToAnimatedImageMetadata(this PngMetadata source) @@ -58,17 +58,25 @@ public static partial class MetadataExtensions }; internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this PngFrameMetadata source) - => new() + { + double delay = source.FrameDelay.ToDouble(); + if (double.IsNaN(delay)) + { + delay = 0; + } + + return new() { ColorTableMode = FrameColorTableMode.Global, - Duration = TimeSpan.FromMilliseconds(source.FrameDelay.ToDouble() * 1000), + Duration = TimeSpan.FromMilliseconds(delay * 1000), DisposalMode = GetMode(source.DisposalMethod), BlendMode = source.BlendMethod == PngBlendMethod.Source ? FrameBlendMode.Source : FrameBlendMode.Over, }; + } private static FrameDisposalMode GetMode(PngDisposalMethod method) => method switch { - PngDisposalMethod.None => FrameDisposalMode.DoNotDispose, + PngDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose, PngDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, PngDisposalMethod.RestoreToPrevious => FrameDisposalMode.RestoreToPrevious, _ => FrameDisposalMode.Unspecified, diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7d573efb62..b0706b14c7 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -581,7 +581,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.header.Height, metadata); - PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata(); + PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngMetadata(); frameMetadata.FromChunk(in frameControl); this.bytesPerPixel = this.CalculateBytesPerPixel(); @@ -630,7 +630,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals pixelRegion.Clear(); } - PngFrameMetadata frameMetadata = frame.Metadata.GetPngFrameMetadata(); + PngFrameMetadata frameMetadata = frame.Metadata.GetPngMetadata(); frameMetadata.FromChunk(currentFrameControl); this.previousScanline?.Dispose(); diff --git a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs b/src/ImageSharp/Formats/Png/PngDisposalMethod.cs index a431e8941f..1537c5cedf 100644 --- a/src/ImageSharp/Formats/Png/PngDisposalMethod.cs +++ b/src/ImageSharp/Formats/Png/PngDisposalMethod.cs @@ -11,7 +11,7 @@ public enum PngDisposalMethod /// /// No disposal is done on this frame before rendering the next; the contents of the output buffer are left as is. /// - None, + DoNotDispose, /// /// The frame's region of the output buffer is to be cleared to fully transparent black before rendering the next frame. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index be6991bab1..a779718a0b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -7,8 +7,10 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Compression.Zlib; +using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.Formats.Png.Filters; +using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -137,7 +139,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// The to encode the image data to. /// The token to request cancellation. public void Encode(Image image, Stream stream, CancellationToken cancellationToken) - where TPixel : unmanaged, IPixel + where TPixel : unmanaged, IPixel { Guard.NotNull(image, nameof(image)); Guard.NotNull(stream, nameof(stream)); @@ -146,7 +148,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable this.height = image.Height; ImageMetadata metadata = image.Metadata; - PngMetadata pngMetadata = metadata.GetFormatMetadata(PngFormat.Instance); + PngMetadata pngMetadata = GetPngMetadata(image); this.SanitizeAndSetEncoderOptions(this.encoder, pngMetadata, out this.use16Bit, out this.bytesPerPixel); stream.Write(PngConstants.HeaderBytes); @@ -234,6 +236,54 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable this.currentScanline?.Dispose(); } + private static PngMetadata GetPngMetadata(Image image) + where TPixel : unmanaged, IPixel + { + if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) + { + return png; + } + + if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) + { + AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata(); + return PngMetadata.FromAnimatedMetadata(ani); + } + + if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) + { + AnimatedImageMetadata ani = webp.ToAnimatedImageMetadata(); + return PngMetadata.FromAnimatedMetadata(ani); + } + + // Return explicit new instance so we do not mutate the original metadata. + return new(); + } + + private static PngFrameMetadata GetPngFrameMetadata(ImageFrame frame) + where TPixel : unmanaged, IPixel + { + if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) + { + return png; + } + + if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) + { + AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata(); + return PngFrameMetadata.FromAnimatedMetadata(ani); + } + + if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) + { + AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); + return PngFrameMetadata.FromAnimatedMetadata(ani); + } + + // Return explicit new instance so we do not mutate the original metadata. + return new(); + } + /// /// Convert transparent pixels, to transparent black pixels, which can yield to better compression in some cases. /// @@ -985,9 +1035,10 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// The containing image data. /// The image frame. /// The frame sequence number. - private FrameControl WriteFrameControlChunk(Stream stream, ImageFrame imageFrame, uint sequenceNumber) + private FrameControl WriteFrameControlChunk(Stream stream, ImageFrame imageFrame, uint sequenceNumber) + where TPixel : unmanaged, IPixel { - PngFrameMetadata frameMetadata = imageFrame.Metadata.GetPngFrameMetadata(); + PngFrameMetadata frameMetadata = GetPngFrameMetadata(imageFrame); // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. FrameControl fcTL = new( diff --git a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs index ca4d8c1f45..dbda4d73c9 100644 --- a/src/ImageSharp/Formats/Png/PngFrameMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngFrameMetadata.cs @@ -34,7 +34,7 @@ public class PngFrameMetadata : IDeepCloneable /// wait before continuing with the processing of the Data Stream. /// The clock starts ticking immediately after the graphic is rendered. /// - public Rational FrameDelay { get; set; } + public Rational FrameDelay { get; set; } = new(0); /// /// Gets or sets the type of frame area disposal to be done after rendering this frame @@ -59,4 +59,20 @@ public class PngFrameMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new PngFrameMetadata(this); + + internal static PngFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) + => new() + { + FrameDelay = new(metadata.Duration.TotalMilliseconds / 1000), + DisposalMethod = GetMode(metadata.DisposalMode), + BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? PngBlendMethod.Source : PngBlendMethod.Over, + }; + + private static PngDisposalMethod GetMode(FrameDisposalMode mode) => mode switch + { + FrameDisposalMode.RestoreToBackground => PngDisposalMethod.RestoreToBackground, + FrameDisposalMode.RestoreToPrevious => PngDisposalMethod.RestoreToPrevious, + FrameDisposalMode.DoNotDispose => PngDisposalMethod.DoNotDispose, + _ => PngDisposalMethod.DoNotDispose, + }; } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 6110cdd0c7..8e2691c104 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -85,4 +85,37 @@ public class PngMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new PngMetadata(this); + + internal static PngMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) + { + // Should the conversion be from a format that uses a 24bit palette entries (gif) + // we need to clone and adjust the color table to allow for transparency. + ReadOnlyMemory? colorTable = metadata.ColorTable; + if (metadata.ColorTable.HasValue) + { + Color[] clone = metadata.ColorTable.Value.ToArray(); + for (int i = 0; i < clone.Length; i++) + { + ref Color c = ref clone[i]; + if (c == metadata.BackgroundColor) + { + // Png treats background as fully empty + c = default; + break; + } + } + + colorTable = clone; + } + + return new() + { + ColorType = colorTable.HasValue ? PngColorType.Palette : null, + BitDepth = colorTable.HasValue + ? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Value.Length), 1, 8) + : null, + ColorTable = colorTable, + RepeatCount = metadata.RepeatCount, + }; + } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index aee5183264..230f69c32d 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -33,7 +33,7 @@ internal readonly struct WebpFrameData height, duration, (flags & 2) == 0 ? WebpBlendingMethod.Over : WebpBlendingMethod.Source, - (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.None) + (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose) { } diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 0821be5777..b9e2519fa4 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -259,7 +259,7 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - WebpMetadata webpMetadata = metadata.GetWebpMetadata(); + WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } } @@ -307,7 +307,7 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(frame); // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = new WebpFrameData( diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 3fea72c07e..e6148a0660 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -333,7 +333,7 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - WebpMetadata webpMetadata = metadata.GetWebpMetadata(); + WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } } @@ -477,7 +477,7 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - WebpFrameMetadata frameMetadata = frame.Metadata.GetWebpMetadata(); + WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(frame); // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = new WebpFrameData( diff --git a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs index 44da191d2d..10c72a3d9c 100644 --- a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs @@ -69,7 +69,7 @@ public static partial class MetadataExtensions private static FrameDisposalMode GetMode(WebpDisposalMethod method) => method switch { WebpDisposalMethod.RestoreToBackground => FrameDisposalMode.RestoreToBackground, - WebpDisposalMethod.None => FrameDisposalMode.DoNotDispose, + WebpDisposalMethod.DoNotDispose => FrameDisposalMode.DoNotDispose, _ => FrameDisposalMode.DoNotDispose, }; } diff --git a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs index 1a8fcbafc9..bb7dd6f279 100644 --- a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs @@ -4,6 +4,8 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp; @@ -13,6 +15,54 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// internal static class WebpCommonUtils { + public static WebpMetadata GetWebpMetadata(Image image) + where TPixel : unmanaged, IPixel + { + if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) + { + return webp; + } + + if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) + { + AnimatedImageMetadata ani = gif.ToAnimatedImageMetadata(); + return WebpMetadata.FromAnimatedMetadata(ani); + } + + if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) + { + AnimatedImageMetadata ani = png.ToAnimatedImageMetadata(); + return WebpMetadata.FromAnimatedMetadata(ani); + } + + // Return explicit new instance so we do not mutate the original metadata. + return new(); + } + + public static WebpFrameMetadata GetWebpFrameMetadata(ImageFrame frame) + where TPixel : unmanaged, IPixel + { + if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) + { + return webp; + } + + if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) + { + AnimatedImageFrameMetadata ani = gif.ToAnimatedImageFrameMetadata(); + return WebpFrameMetadata.FromAnimatedMetadata(ani); + } + + if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) + { + AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); + return WebpFrameMetadata.FromAnimatedMetadata(ani); + } + + // Return explicit new instance so we do not mutate the original metadata. + return new(); + } + /// /// Checks if the pixel row is not opaque. /// @@ -27,7 +77,7 @@ internal static class WebpCommonUtils int length = (row.Length * 4) - 3; fixed (byte* src = rowBytes) { - var alphaMaskVector256 = Vector256.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector256 alphaMaskVector256 = Vector256.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); Vector256 all0x80Vector256 = Vector256.Create((byte)0x80).AsByte(); for (; i + 128 <= length; i += 128) @@ -124,7 +174,7 @@ internal static class WebpCommonUtils private static unsafe bool IsNoneOpaque64Bytes(byte* src, int i) { - var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector128 alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); @@ -144,7 +194,7 @@ internal static class WebpCommonUtils private static unsafe bool IsNoneOpaque32Bytes(byte* src, int i) { - var alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); + Vector128 alphaMask = Vector128.Create(0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255, 0, 0, 0, 255); Vector128 a0 = Sse2.LoadVector128(src + i).AsByte(); Vector128 a1 = Sse2.LoadVector128(src + i + 16).AsByte(); diff --git a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs index 397c2ee502..47cc83951d 100644 --- a/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpDisposalMethod.cs @@ -11,7 +11,7 @@ public enum WebpDisposalMethod /// /// Do not dispose. Leave the canvas as is. /// - None = 0, + DoNotDispose = 0, /// /// Dispose to background color. Fill the rectangle on the canvas covered by the current frame with background color specified in the ANIM chunk. diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 47712071bf..8374870473 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -123,7 +123,7 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals } else { - WebpMetadata webpMetadata = image.Metadata.GetWebpMetadata(); + WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); lossless = webpMetadata.FileFormat == WebpFileFormatType.Lossless; } diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index ef21d8b6fe..667b8f8f46 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -44,4 +44,12 @@ public class WebpFrameMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new WebpFrameMetadata(this); + + internal static WebpFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) + => new() + { + FrameDelay = (uint)metadata.Duration.Milliseconds, + BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendingMethod.Source : WebpBlendingMethod.Over, + DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose + }; } diff --git a/src/ImageSharp/Formats/Webp/WebpMetadata.cs b/src/ImageSharp/Formats/Webp/WebpMetadata.cs index 9d0d8d08d2..536ea09294 100644 --- a/src/ImageSharp/Formats/Webp/WebpMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpMetadata.cs @@ -46,4 +46,12 @@ public class WebpMetadata : IDeepCloneable /// public IDeepCloneable DeepClone() => new WebpMetadata(this); + + internal static WebpMetadata FromAnimatedMetadata(AnimatedImageMetadata metadata) + => new() + { + FileFormat = WebpFileFormatType.Lossless, + BackgroundColor = metadata.BackgroundColor, + RepeatCount = metadata.RepeatCount + }; } diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index f75664903d..8aa166d16c 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -200,7 +200,7 @@ internal sealed class EuclideanPixelMap : IDisposable } [MethodImpl(InliningOptions.ShortMethod)] - public void Add(Rgba32 rgba, byte index) + public readonly void Add(Rgba32 rgba, byte index) { int r = rgba.R >> RgbShift; int g = rgba.G >> RgbShift; @@ -211,7 +211,7 @@ internal sealed class EuclideanPixelMap : IDisposable } [MethodImpl(InliningOptions.ShortMethod)] - public bool TryGetValue(Rgba32 rgba, out short match) + public readonly bool TryGetValue(Rgba32 rgba, out short match) { int r = rgba.R >> RgbShift; int g = rgba.G >> RgbShift; @@ -226,7 +226,7 @@ internal sealed class EuclideanPixelMap : IDisposable /// Clears the cache resetting each entry to empty. /// [MethodImpl(InliningOptions.ShortMethod)] - public void Clear() => this.table.GetSpan().Fill(-1); + public readonly void Clear() => this.table.GetSpan().Fill(-1); [MethodImpl(InliningOptions.ShortMethod)] private static int GetPaletteIndex(int r, int g, int b, int a) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index 65d186c914..cd485b5fab 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -245,7 +247,7 @@ public class GifEncoderTests int count = 0; foreach (ImageFrame frame in image.Frames) { - if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata _)) + if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) { count++; } @@ -261,7 +263,7 @@ public class GifEncoderTests count = 0; foreach (ImageFrame frame in image2.Frames) { - if (frame.Metadata.TryGetGifFrameMetadata(out GifFrameMetadata _)) + if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata _)) { count++; } @@ -269,4 +271,90 @@ public class GifEncoderTests Assert.Equal(image2.Frames.Count, count); } + + [Theory] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromPng(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + + using MemoryStream memStream = new(); + image.Save(memStream, new GifEncoder()); + memStream.Position = 0; + + using Image output = Image.Load(memStream); + + // TODO: Find a better way to compare. + // The image has been visually checked but the quantization and frame trimming pattern used in the gif encoder + // means we cannot use an exact comparison nor replicate using the quantizing processor. + ImageComparer.TolerantPercentage(1.51f).VerifySimilarity(output, image); + + PngMetadata png = image.Metadata.GetPngMetadata(); + GifMetadata gif = output.Metadata.GetGifMetadata(); + + Assert.Equal(png.RepeatCount, gif.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + PngFrameMetadata pngF = image.Frames[i].Metadata.GetPngMetadata(); + GifFrameMetadata gifF = output.Frames[i].Metadata.GetGifMetadata(); + + Assert.Equal((int)(pngF.FrameDelay.ToDouble() * 100), gifF.FrameDelay); + + switch (pngF.DisposalMethod) + { + case PngDisposalMethod.RestoreToBackground: + Assert.Equal(GifDisposalMethod.RestoreToBackground, gifF.DisposalMethod); + break; + case PngDisposalMethod.DoNotDispose: + default: + Assert.Equal(GifDisposalMethod.NotDispose, gifF.DisposalMethod); + break; + } + } + } + + [Theory] + [WithFile(TestImages.Webp.Lossless.Animated, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromWebp(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(WebpDecoder.Instance); + + using MemoryStream memStream = new(); + image.Save(memStream, new GifEncoder()); + memStream.Position = 0; + + using Image output = Image.Load(memStream); + + // TODO: Find a better way to compare. + // The image has been visually checked but the quantization and frame trimming pattern used in the gif encoder + // means we cannot use an exact comparison nor replicate using the quantizing processor. + ImageComparer.TolerantPercentage(0.776f).VerifySimilarity(output, image); + + WebpMetadata webp = image.Metadata.GetWebpMetadata(); + GifMetadata gif = output.Metadata.GetGifMetadata(); + + Assert.Equal(webp.RepeatCount, gif.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + WebpFrameMetadata webpF = image.Frames[i].Metadata.GetWebpMetadata(); + GifFrameMetadata gifF = output.Frames[i].Metadata.GetGifMetadata(); + + Assert.Equal(webpF.FrameDelay, (uint)(gifF.FrameDelay * 10)); + + switch (webpF.DisposalMethod) + { + case WebpDisposalMethod.RestoreToBackground: + Assert.Equal(GifDisposalMethod.RestoreToBackground, gifF.DisposalMethod); + break; + case WebpDisposalMethod.DoNotDispose: + default: + Assert.Equal(GifDisposalMethod.NotDispose, gifF.DisposalMethod); + break; + } + } + } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index a6840b33e4..45dd30b3b0 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -5,6 +5,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Processing.Processors.Quantization; @@ -454,10 +455,6 @@ public partial class PngEncoderTests memStream.Position = 0; image.DebugSave(provider: provider, encoder: PngEncoder, null, false); - image.DebugSave(provider: provider, encoder: new GifEncoder(), "gif", false); - - string path = provider.Utility.GetTestOutputFileName("gif"); - image.Save(path); using Image output = Image.Load(memStream); ImageComparer.Exact.VerifySimilarity(output, image); @@ -472,8 +469,8 @@ public partial class PngEncoderTests for (int i = 0; i < image.Frames.Count; i++) { - PngFrameMetadata originalFrameMetadata = image.Frames[i].Metadata.GetPngFrameMetadata(); - PngFrameMetadata outputFrameMetadata = output.Frames[i].Metadata.GetPngFrameMetadata(); + PngFrameMetadata originalFrameMetadata = image.Frames[i].Metadata.GetPngMetadata(); + PngFrameMetadata outputFrameMetadata = output.Frames[i].Metadata.GetPngMetadata(); Assert.Equal(originalFrameMetadata.FrameDelay, outputFrameMetadata.FrameDelay); Assert.Equal(originalFrameMetadata.BlendMethod, outputFrameMetadata.BlendMethod); @@ -481,6 +478,106 @@ public partial class PngEncoderTests } } + [Theory] + [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(GifDecoder.Instance); + using MemoryStream memStream = new(); + + image.Save(memStream, PngEncoder); + memStream.Position = 0; + + image.Save(provider.Utility.GetTestOutputFileName("png"), new PngEncoder()); + image.Save(provider.Utility.GetTestOutputFileName("gif"), new GifEncoder()); + + using Image output = Image.Load(memStream); + + // TODO: Find a better way to compare. + // The image has been visually checked but the quantization pattern used in the png encoder + // means we cannot use an exact comparison nor replicate using the quantizing processor. + ImageComparer.TolerantPercentage(0.12f).VerifySimilarity(output, image); + + GifMetadata gif = image.Metadata.GetGifMetadata(); + PngMetadata png = output.Metadata.GetPngMetadata(); + + Assert.Equal(gif.RepeatCount, png.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + GifFrameMetadata gifF = image.Frames[i].Metadata.GetGifMetadata(); + PngFrameMetadata pngF = output.Frames[i].Metadata.GetPngMetadata(); + + Assert.Equal(gifF.FrameDelay, (int)(pngF.FrameDelay.ToDouble() * 100)); + + switch (gifF.DisposalMethod) + { + case GifDisposalMethod.RestoreToBackground: + Assert.Equal(PngDisposalMethod.RestoreToBackground, pngF.DisposalMethod); + break; + case GifDisposalMethod.RestoreToPrevious: + Assert.Equal(PngDisposalMethod.RestoreToPrevious, pngF.DisposalMethod); + break; + case GifDisposalMethod.Unspecified: + case GifDisposalMethod.NotDispose: + default: + Assert.Equal(PngDisposalMethod.DoNotDispose, pngF.DisposalMethod); + break; + } + } + } + + [Theory] + [WithFile(TestImages.Webp.Lossless.Animated, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromWebp(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(WebpDecoder.Instance); + + using MemoryStream memStream = new(); + image.Save(memStream, PngEncoder); + memStream.Position = 0; + + using Image output = Image.Load(memStream); + ImageComparer.Exact.VerifySimilarity(output, image); + + WebpMetadata webp = image.Metadata.GetWebpMetadata(); + PngMetadata png = output.Metadata.GetPngMetadata(); + + Assert.Equal(webp.RepeatCount, png.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + WebpFrameMetadata webpF = image.Frames[i].Metadata.GetWebpMetadata(); + PngFrameMetadata pngF = output.Frames[i].Metadata.GetPngMetadata(); + + Assert.Equal(webpF.FrameDelay, (uint)(pngF.FrameDelay.ToDouble() * 1000)); + + switch (webpF.BlendMethod) + { + case WebpBlendingMethod.Source: + Assert.Equal(PngBlendMethod.Source, pngF.BlendMethod); + break; + case WebpBlendingMethod.Over: + default: + Assert.Equal(PngBlendMethod.Over, pngF.BlendMethod); + break; + } + + switch (webpF.DisposalMethod) + { + case WebpDisposalMethod.RestoreToBackground: + Assert.Equal(PngDisposalMethod.RestoreToBackground, pngF.DisposalMethod); + break; + case WebpDisposalMethod.DoNotDispose: + default: + Assert.Equal(PngDisposalMethod.DoNotDispose, pngF.DisposalMethod); + break; + } + } + } + [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 0ad684b277..0fafdbe161 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats.Gif; +using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -60,6 +62,97 @@ public class WebpEncoderTests encoded.CompareToReferenceOutput(ImageComparer.Tolerant(0.01f), provider, null, "webp"); } + [Theory] + [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(GifDecoder.Instance); + using MemoryStream memStream = new(); + + image.Save(memStream, new WebpEncoder()); + memStream.Position = 0; + + using Image output = Image.Load(memStream); + + ImageComparer.Exact.VerifySimilarity(output, image); + + GifMetadata gif = image.Metadata.GetGifMetadata(); + WebpMetadata webp = output.Metadata.GetWebpMetadata(); + + Assert.Equal(gif.RepeatCount, webp.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + GifFrameMetadata gifF = image.Frames[i].Metadata.GetGifMetadata(); + WebpFrameMetadata webpF = output.Frames[i].Metadata.GetWebpMetadata(); + + Assert.Equal(gifF.FrameDelay, (int)(webpF.FrameDelay / 10)); + + switch (gifF.DisposalMethod) + { + case GifDisposalMethod.RestoreToBackground: + Assert.Equal(WebpDisposalMethod.RestoreToBackground, webpF.DisposalMethod); + break; + case GifDisposalMethod.RestoreToPrevious: + case GifDisposalMethod.Unspecified: + case GifDisposalMethod.NotDispose: + default: + Assert.Equal(WebpDisposalMethod.DoNotDispose, webpF.DisposalMethod); + break; + } + } + } + + [Theory] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void Encode_AnimatedFormatTransform_FromPng(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + + using MemoryStream memStream = new(); + image.Save(memStream, new WebpEncoder()); + memStream.Position = 0; + + using Image output = Image.Load(memStream); + ImageComparer.Exact.VerifySimilarity(output, image); + PngMetadata png = image.Metadata.GetPngMetadata(); + WebpMetadata webp = output.Metadata.GetWebpMetadata(); + + Assert.Equal(png.RepeatCount, webp.RepeatCount); + + for (int i = 0; i < image.Frames.Count; i++) + { + PngFrameMetadata pngF = image.Frames[i].Metadata.GetPngMetadata(); + WebpFrameMetadata webpF = output.Frames[i].Metadata.GetWebpMetadata(); + + Assert.Equal((uint)(pngF.FrameDelay.ToDouble() * 1000), webpF.FrameDelay); + + switch (pngF.BlendMethod) + { + case PngBlendMethod.Source: + Assert.Equal(WebpBlendingMethod.Source, webpF.BlendMethod); + break; + case PngBlendMethod.Over: + default: + Assert.Equal(WebpBlendingMethod.Over, webpF.BlendMethod); + break; + } + + switch (pngF.DisposalMethod) + { + case PngDisposalMethod.RestoreToBackground: + Assert.Equal(WebpDisposalMethod.RestoreToBackground, webpF.DisposalMethod); + break; + case PngDisposalMethod.DoNotDispose: + default: + Assert.Equal(WebpDisposalMethod.DoNotDispose, webpF.DisposalMethod); + break; + } + } + } + [Theory] [WithFile(Flag, PixelTypes.Rgba32, WebpFileFormatType.Lossy)] // If its not a webp input image, it should default to lossy. [WithFile(Lossless.NoTransform1, PixelTypes.Rgba32, WebpFileFormatType.Lossless)] From 7f4b4575210bb580826ea0fefad37c4b605a9590 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 17 Nov 2023 13:31:36 +1000 Subject: [PATCH 032/219] Default loop count should be 1 --- src/ImageSharp/Formats/Png/PngMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 8e2691c104..7f4052846a 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -81,7 +81,7 @@ public class PngMetadata : IDeepCloneable /// /// Gets or sets the number of times to loop this APNG. 0 indicates infinite looping. /// - public uint RepeatCount { get; set; } + public uint RepeatCount { get; set; } = 1; /// public IDeepCloneable DeepClone() => new PngMetadata(this); From 560886b3d0775dfb312d1815fc21a4c90089d6f3 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Tue, 12 Sep 2023 10:19:42 +0200 Subject: [PATCH 033/219] Update to net8 --- .github/workflows/build-and-test.yml | 31 ++++---------- .github/workflows/code-coverage.yml | 2 +- README.md | 4 +- src/ImageSharp/Common/Helpers/Numerics.cs | 19 --------- .../CodeAnalysis/UnscopedRefAttribute.cs | 42 ------------------- .../Formats/Webp/Lossy/LossyUtils.cs | 13 +----- src/ImageSharp/ImageSharp.csproj | 4 +- .../ImageSharp.Benchmarks.csproj | 6 +-- .../ImageSharp.Tests.ProfilingSandbox.csproj | 4 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 4 +- 10 files changed, 21 insertions(+), 108 deletions(-) delete mode 100644 src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b375574018..6f9dc1d42b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -19,44 +19,29 @@ jobs: - ${{ contains(github.event.pull_request.labels.*.name, 'arch:arm32') || contains(github.event.pull_request.labels.*.name, 'arch:arm64') }} options: - os: ubuntu-latest - framework: net7.0 - sdk: 7.0.x + framework: net8.0 + sdk: 8.0.x sdk-preview: true runtime: -x64 codecov: false - os: macos-latest - framework: net7.0 - sdk: 7.0.x + framework: net8.0 + sdk: 8.0.x sdk-preview: true runtime: -x64 codecov: false - os: windows-latest - framework: net7.0 - sdk: 7.0.x + framework: net8.0 + sdk: 8.0.x sdk-preview: true runtime: -x64 codecov: false - os: buildjet-4vcpu-ubuntu-2204-arm - framework: net7.0 - sdk: 7.0.x + framework: net8.0 + sdk: 8.0.x sdk-preview: true runtime: -x64 codecov: false - - os: ubuntu-latest - framework: net6.0 - sdk: 6.0.x - runtime: -x64 - codecov: false - - os: macos-latest - framework: net6.0 - sdk: 6.0.x - runtime: -x64 - codecov: false - - os: windows-latest - framework: net6.0 - sdk: 6.0.x - runtime: -x64 - codecov: false exclude: - isARM: false options: diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index e551afbd6d..bbaea3a61b 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -10,7 +10,7 @@ jobs: matrix: options: - os: ubuntu-latest - framework: net6.0 + framework: net8.0 runtime: -x64 codecov: true diff --git a/README.md b/README.md index fa51d57cdf..cf58b6b14b 100644 --- a/README.md +++ b/README.md @@ -21,7 +21,7 @@ Designed to simplify image processing, ImageSharp brings you an incredibly power ImageSharp is designed from the ground up to be flexible and extensible. The library provides API endpoints for common image processing operations and the building blocks to allow for the development of additional operations. -Built against [.NET 6](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. +Built against [.NET 8](https://docs.microsoft.com/en-us/dotnet/standard/net-standard), ImageSharp can be used in device, cloud, and embedded/IoT scenarios. ## License @@ -64,7 +64,7 @@ If you prefer, you can compile ImageSharp yourself (please do and help!) - Using [Visual Studio 2022](https://visualstudio.microsoft.com/vs/) - Make sure you have the latest version installed - - Make sure you have [the .NET 7 SDK](https://www.microsoft.com/net/core#windows) installed + - Make sure you have [the .NET 8 SDK](https://www.microsoft.com/net/core#windows) installed Alternatively, you can work from command line and/or with a lightweight editor on **both Linux/Unix and Windows**: diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index aba3c0abdc..293997c4de 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -908,25 +908,6 @@ internal static class Numerics return Sse2.ConvertToInt32(vsum); } - /// - /// Reduces elements of the vector into one sum. - /// - /// The accumulator to reduce. - /// The sum of all elements. - [MethodImpl(InliningOptions.ShortMethod)] - public static int ReduceSumArm(Vector128 accumulator) - { - if (AdvSimd.Arm64.IsSupported) - { - Vector64 sum = AdvSimd.Arm64.AddAcross(accumulator); - return (int)AdvSimd.Extract(sum, 0); - } - - Vector128 sum2 = AdvSimd.AddPairwiseWidening(accumulator); - Vector64 sum3 = AdvSimd.Add(sum2.GetLower().AsUInt32(), sum2.GetUpper().AsUInt32()); - return (int)AdvSimd.Extract(sum3, 0); - } - /// /// Reduces even elements of the vector into one sum. /// diff --git a/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs b/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs deleted file mode 100644 index dc2c7bd196..0000000000 --- a/src/ImageSharp/Diagnostics/CodeAnalysis/UnscopedRefAttribute.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. -#if NET6_0 -// Licensed to the .NET Foundation under one or more agreements. -// The .NET Foundation licenses this file to you under the MIT license. -namespace System.Diagnostics.CodeAnalysis -{ - /// - /// Used to indicate a byref escapes and is not scoped. - /// - /// - /// - /// There are several cases where the C# compiler treats a as implicitly - /// - where the compiler does not allow the to escape the method. - /// - /// - /// For example: - /// - /// for instance methods. - /// parameters that refer to types. - /// parameters. - /// - /// - /// - /// This attribute is used in those instances where the should be allowed to escape. - /// - /// - /// Applying this attribute, in any form, has impact on consumers of the applicable API. It is necessary for - /// API authors to understand the lifetime implications of applying this attribute and how it may impact their users. - /// - /// - [global::System.AttributeUsage( - global::System.AttributeTargets.Method | - global::System.AttributeTargets.Property | - global::System.AttributeTargets.Parameter, - AllowMultiple = false, - Inherited = false)] - internal sealed class UnscopedRefAttribute : global::System.Attribute - { - } -} -#endif diff --git a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs index de3f1586af..aae4181ce0 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/LossyUtils.cs @@ -230,11 +230,7 @@ internal static class LossyUtils } } -#if NET7_0_OR_GREATER return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } [MethodImpl(InliningOptions.ShortMethod)] @@ -252,11 +248,7 @@ internal static class LossyUtils } } -#if NET7_0_OR_GREATER return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } [MethodImpl(InliningOptions.ShortMethod)] @@ -275,11 +267,8 @@ internal static class LossyUtils Vector128 sum2 = AdvSimd.AddPairwiseWidening(prod2); Vector128 sum = AdvSimd.Add(sum1, sum2); -#if NET7_0_OR_GREATER + return (int)Vector128.Sum(sum); -#else - return Numerics.ReduceSumArm(sum); -#endif } // Load all 4x4 pixels into a single Vector128 diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index b08c27c41b..12da6cf532 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -29,13 +29,13 @@ - net7.0;net6.0 + net8.0 true - net6.0 + net8.0 true diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 0ba2f4b949..22a2777a6a 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -11,7 +11,7 @@ false Debug;Release - + @@ -23,12 +23,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 492ce36b81..dfa01b8be1 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -19,12 +19,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index dc081e0bea..491c4da872 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -12,12 +12,12 @@ - net7.0;net6.0 + net8.0 - net6.0 + net8.0 From 807b5d9555eb776615ef6c2049fa6e26c2cc7c11 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 10:56:56 +0100 Subject: [PATCH 034/219] Update build sdk to net8 --- .github/workflows/build-and-test.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 6f9dc1d42b..d4c3888d42 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -96,14 +96,14 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: | - 6.0.x + 8.0.x - name: DotNet Setup Preview if: ${{ matrix.options.sdk-preview == true }} uses: actions/setup-dotnet@v3 with: dotnet-version: | - 7.0.x + 8.0.x - name: DotNet Build if: ${{ matrix.options.sdk-preview != true }} From 836744f47b300787fdbe97711b2a41b390f3e307 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 11:00:13 +0100 Subject: [PATCH 035/219] use win-x64 as rid --- .github/workflows/code-coverage.yml | 2 +- .../ImageSharp.Tests.ProfilingSandbox.csproj | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index bbaea3a61b..7624e86b67 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -58,7 +58,7 @@ jobs: uses: actions/setup-dotnet@v3 with: dotnet-version: | - 6.0.x + 8.0.x - name: DotNet Build shell: pwsh diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index dfa01b8be1..76891b4bbb 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -7,7 +7,7 @@ Exe false SixLabors.ImageSharp.Tests.ProfilingSandbox - win7-x64 + win-x64 SixLabors.ImageSharp.Tests.ProfilingSandbox.Program false From 0b49cb01271d08919120fb6a53957611ddff56ba Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 13:43:25 +0100 Subject: [PATCH 036/219] Use C# 12.0 --- src/ImageSharp/ImageSharp.csproj | 1 + 1 file changed, 1 insertion(+) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 12da6cf532..a1c7e6175f 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -17,6 +17,7 @@ + 12.0 enable Nullable From 69951a59c5ab7d120ac59e78ca91e9c6beb3839d Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 13:55:00 +0100 Subject: [PATCH 037/219] remove sdk-preview --- .github/workflows/build-and-test.yml | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d4c3888d42..7c7791347d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -21,25 +21,21 @@ jobs: - os: ubuntu-latest framework: net8.0 sdk: 8.0.x - sdk-preview: true runtime: -x64 codecov: false - os: macos-latest framework: net8.0 sdk: 8.0.x - sdk-preview: true runtime: -x64 codecov: false - os: windows-latest framework: net8.0 sdk: 8.0.x - sdk-preview: true runtime: -x64 codecov: false - os: buildjet-4vcpu-ubuntu-2204-arm framework: net8.0 sdk: 8.0.x - sdk-preview: true runtime: -x64 codecov: false exclude: From 4564831d10dd27ffc123be025e3ee89bffb3c0ab Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 14:13:31 +0100 Subject: [PATCH 038/219] Fix build errors --- .editorconfig | 2 ++ .../Advanced/ParallelRowIterator.Wrappers.cs | 4 ++-- src/ImageSharp/Advanced/ParallelRowIterator.cs | 10 +++++----- src/ImageSharp/Common/Helpers/DebugGuard.cs | 2 ++ src/ImageSharp/Configuration.cs | 5 +---- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 5 +---- .../Allocators/Internals/SharedArrayPoolBuffer{T}.cs | 2 ++ .../PixelFormats/PixelImplementations/Abgr32.cs | 2 +- .../PixelFormats/PixelImplementations/Argb32.cs | 2 +- .../PixelFormats/PixelImplementations/Bgra32.cs | 2 +- .../PixelFormats/PixelImplementations/La16.cs | 2 +- .../PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelFormats/PixelImplementations/Rgba32.cs | 2 +- .../PixelFormats/PixelImplementations/Rgba64.cs | 4 ++-- .../Processing/Processors/Dithering/ErrorDither.cs | 2 +- .../PixelRowDelegateProcessor{TPixel,TDelegate}.cs | 2 +- .../Processors/Filters/FilterProcessor{TPixel}.cs | 2 +- .../Processors/Quantization/OctreeQuantizer{TPixel}.cs | 2 +- .../Quantization/PaletteQuantizer{TPixel}.cs | 2 +- .../Processors/Quantization/QuantizerUtilities.cs | 2 +- .../Processors/Quantization/WuQuantizer{TPixel}.cs | 2 +- .../ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 1 + 22 files changed, 31 insertions(+), 30 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2e3045fb17..ebda51e371 100644 --- a/.editorconfig +++ b/.editorconfig @@ -422,6 +422,8 @@ dotnet_naming_rule.parameters_rule.symbols = parameters_group dotnet_naming_rule.parameters_rule.style = camel_case_style dotnet_naming_rule.parameters_rule.severity = warning + +dotnet_diagnostics.CA1857.severity = none ########################################## # License ########################################## diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs index 9629b0097e..a959faa3b6 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.Wrappers.cs @@ -51,7 +51,7 @@ public static partial class ParallelRowIterator for (int y = yMin; y < yMax; y++) { // Skip the safety copy when invoking a potentially impure method on a readonly field - Unsafe.AsRef(this.action).Invoke(y); + Unsafe.AsRef(in this.action).Invoke(y); } } } @@ -102,7 +102,7 @@ public static partial class ParallelRowIterator for (int y = yMin; y < yMax; y++) { - Unsafe.AsRef(this.action).Invoke(y, span); + Unsafe.AsRef(in this.action).Invoke(y, span); } } } diff --git a/src/ImageSharp/Advanced/ParallelRowIterator.cs b/src/ImageSharp/Advanced/ParallelRowIterator.cs index 657654a84b..1284a3a898 100644 --- a/src/ImageSharp/Advanced/ParallelRowIterator.cs +++ b/src/ImageSharp/Advanced/ParallelRowIterator.cs @@ -58,7 +58,7 @@ public static partial class ParallelRowIterator { for (int y = top; y < bottom; y++) { - Unsafe.AsRef(operation).Invoke(y); + Unsafe.AsRef(in operation).Invoke(y); } return; @@ -118,7 +118,7 @@ public static partial class ParallelRowIterator int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); MemoryAllocator allocator = parallelSettings.MemoryAllocator; - int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); + int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle); // Avoid TPL overhead in this trivial case: if (numOfSteps == 1) @@ -128,7 +128,7 @@ public static partial class ParallelRowIterator for (int y = top; y < bottom; y++) { - Unsafe.AsRef(operation).Invoke(y, span); + Unsafe.AsRef(in operation).Invoke(y, span); } return; @@ -245,7 +245,7 @@ public static partial class ParallelRowIterator int maxSteps = DivideCeil(width * (long)height, parallelSettings.MinimumPixelsProcessedPerTask); int numOfSteps = Math.Min(parallelSettings.MaxDegreeOfParallelism, maxSteps); MemoryAllocator allocator = parallelSettings.MemoryAllocator; - int bufferLength = Unsafe.AsRef(operation).GetRequiredBufferLength(rectangle); + int bufferLength = Unsafe.AsRef(in operation).GetRequiredBufferLength(rectangle); // Avoid TPL overhead in this trivial case: if (numOfSteps == 1) @@ -253,7 +253,7 @@ public static partial class ParallelRowIterator var rows = new RowInterval(top, bottom); using IMemoryOwner buffer = allocator.Allocate(bufferLength); - Unsafe.AsRef(operation).Invoke(in rows, buffer.Memory.Span); + Unsafe.AsRef(in operation).Invoke(in rows, buffer.Memory.Span); return; } diff --git a/src/ImageSharp/Common/Helpers/DebugGuard.cs b/src/ImageSharp/Common/Helpers/DebugGuard.cs index be2daa139e..990b21c99e 100644 --- a/src/ImageSharp/Common/Helpers/DebugGuard.cs +++ b/src/ImageSharp/Common/Helpers/DebugGuard.cs @@ -33,10 +33,12 @@ internal static partial class DebugGuard [Conditional("DEBUG")] public static void NotDisposed(bool isDisposed, string objectName) { +#pragma warning disable CA1513 if (isDisposed) { throw new ObjectDisposedException(objectName); } +#pragma warning restore CA1513 } /// diff --git a/src/ImageSharp/Configuration.cs b/src/ImageSharp/Configuration.cs index 39fcef9c40..1ca5d0a46b 100644 --- a/src/ImageSharp/Configuration.cs +++ b/src/ImageSharp/Configuration.cs @@ -87,10 +87,7 @@ public sealed class Configuration get => this.streamProcessingBufferSize; set { - if (value <= 0) - { - throw new ArgumentOutOfRangeException(nameof(this.StreamProcessingBufferSize)); - } + ArgumentOutOfRangeException.ThrowIfNegativeOrZero(value); this.streamProcessingBufferSize = value; } diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 95f7fde32c..7fc2a1f45e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -176,10 +176,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals /// is . private void WriteDefineHuffmanTables(JpegHuffmanTableConfig[] tableConfigs, HuffmanScanEncoder scanEncoder, Span buffer) { - if (tableConfigs is null) - { - throw new ArgumentNullException(nameof(tableConfigs)); - } + ArgumentNullException.ThrowIfNull(tableConfigs); int markerlen = 2; diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index f9434ee941..c0a0c5d272 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -59,10 +59,12 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted [MemberNotNull(nameof(Array))] private void CheckDisposed() { +#pragma warning disable CA1513 if (this.Array == null) { throw new ObjectDisposedException("SharedArrayPoolBuffer"); } +#pragma warning restore CA1513 } private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 4891abba8c..8bd24c7a01 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -129,7 +129,7 @@ public partial struct Abgr32 : IPixel, IPackedVector public uint Abgr { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 0c99adb52d..fa8af98a0b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -129,7 +129,7 @@ public partial struct Argb32 : IPixel, IPackedVector public uint Argb { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 6b859cda64..d7222f2ef8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -85,7 +85,7 @@ public partial struct Bgra32 : IPixel, IPackedVector public uint Bgra { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 7597677a26..58aeb61890 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -45,7 +45,7 @@ public partial struct La16 : IPixel, IPackedVector /// public ushort PackedValue { - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); set => Unsafe.As(ref this) = value; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index cb8fad228d..db7f433293 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -45,7 +45,7 @@ public partial struct La32 : IPixel, IPackedVector public uint PackedValue { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index a652c2b339..75fe8f3f4e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -124,7 +124,7 @@ public partial struct Rgba32 : IPixel, IPackedVector public uint Rgba { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 81c9591480..75235c9007 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -152,7 +152,7 @@ public partial struct Rgba64 : IPixel, IPackedVector public Rgb48 Rgb { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; @@ -162,7 +162,7 @@ public partial struct Rgba64 : IPixel, IPackedVector public ulong PackedValue { [MethodImpl(InliningOptions.ShortMethod)] - readonly get => Unsafe.As(ref Unsafe.AsRef(this)); + readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); [MethodImpl(InliningOptions.ShortMethod)] set => Unsafe.As(ref this) = value; diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 754aac90ea..287a8d197c 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -143,7 +143,7 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I for (int x = bounds.Left; x < bounds.Right; x++) { ref TPixel sourcePixel = ref Unsafe.Add(ref sourceRowRef, (uint)x); - TPixel transformed = Unsafe.AsRef(processor).GetPaletteColor(sourcePixel); + TPixel transformed = Unsafe.AsRef(in processor).GetPaletteColor(sourcePixel); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); sourcePixel = transformed; } diff --git a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs index f59b95050e..36bb327cf2 100644 --- a/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs +++ b/src/ImageSharp/Processing/Processors/Effects/PixelRowDelegateProcessor{TPixel,TDelegate}.cs @@ -96,7 +96,7 @@ internal sealed class PixelRowDelegateProcessor : ImageProces PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, this.modifiers); // Run the user defined pixel shader to the current row of pixels - Unsafe.AsRef(this.rowProcessor).Invoke(span, new Point(this.startX, y)); + Unsafe.AsRef(in this.rowProcessor).Invoke(span, new Point(this.startX, y)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, this.modifiers); } diff --git a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs index 5ad245e3ce..5109139647 100644 --- a/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/FilterProcessor{TPixel}.cs @@ -78,7 +78,7 @@ internal class FilterProcessor : ImageProcessor Span rowSpan = this.source.DangerousGetRowSpan(y).Slice(this.startX, span.Length); PixelOperations.Instance.ToVector4(this.configuration, rowSpan, span, PixelConversionModifiers.Scale); - ColorNumerics.Transform(span, ref Unsafe.AsRef(this.matrix)); + ColorNumerics.Transform(span, ref Unsafe.AsRef(in this.matrix)); PixelOperations.Instance.FromVector4Destructive(this.configuration, span, rowSpan, PixelConversionModifiers.Scale); } diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index 1136fbc9da..e81ad59d44 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -128,7 +128,7 @@ public struct OctreeQuantizer : IQuantizer /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs index 3df80ea9b7..092975d28a 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/PaletteQuantizer{TPixel}.cs @@ -56,7 +56,7 @@ internal readonly struct PaletteQuantizer : IQuantizer /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// [MethodImpl(InliningOptions.ShortMethod)] diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index 53203f94a0..55154d6e2f 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -161,7 +161,7 @@ public static class QuantizerUtilities for (int x = bounds.Left; x < bounds.Right; x++) { - destinationRow[x - offsetX] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); + destinationRow[x - offsetX] = Unsafe.AsRef(in quantizer).GetQuantizedColor(sourceRow[x], out TPixel _); } } diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index 524153804c..46c3f03d69 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -167,7 +167,7 @@ internal struct WuQuantizer : IQuantizer /// [MethodImpl(InliningOptions.ShortMethod)] public readonly IndexedImageFrame QuantizeFrame(ImageFrame source, Rectangle bounds) - => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(this), source, bounds); + => QuantizerUtilities.QuantizeFrame(ref Unsafe.AsRef(in this), source, bounds); /// public readonly byte GetQuantizedColor(TPixel color, out TPixel match) diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 22a2777a6a..5686003116 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -10,6 +10,7 @@ false Debug;Release + 12.0 From 85c0b618b5432a1c31d41558f59913bc6966d760 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 14:17:10 +0100 Subject: [PATCH 039/219] Disable CS1859 --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index ebda51e371..2007532919 100644 --- a/.editorconfig +++ b/.editorconfig @@ -424,6 +424,7 @@ dotnet_naming_rule.parameters_rule.severity = warning dotnet_diagnostics.CA1857.severity = none +dotnet_diagnostics.CA1859.severity = none ########################################## # License ########################################## From 1be9491023c05000952d8f20c55fa57d3a4fe986 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 14:23:16 +0100 Subject: [PATCH 040/219] Disable the rules in the ruleset --- .editorconfig | 3 --- src/ImageSharp.ruleset | 6 +++++- 2 files changed, 5 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2007532919..2e3045fb17 100644 --- a/.editorconfig +++ b/.editorconfig @@ -422,9 +422,6 @@ dotnet_naming_rule.parameters_rule.symbols = parameters_group dotnet_naming_rule.parameters_rule.style = camel_case_style dotnet_naming_rule.parameters_rule.severity = warning - -dotnet_diagnostics.CA1857.severity = none -dotnet_diagnostics.CA1859.severity = none ########################################## # License ########################################## diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index e88c43f838..11f5041589 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,7 +1,11 @@  + + + + - \ No newline at end of file + From d1c3c31258e8ce734b53e6d926af5c06005df640 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sat, 18 Nov 2023 14:29:43 +0100 Subject: [PATCH 041/219] Nextfixes --- src/ImageSharp/Formats/ImageFormatManager.cs | 5 +---- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +-- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/ImageFormatManager.cs b/src/ImageSharp/Formats/ImageFormatManager.cs index 0ee4bc79b9..b6b5f87797 100644 --- a/src/ImageSharp/Formats/ImageFormatManager.cs +++ b/src/ImageSharp/Formats/ImageFormatManager.cs @@ -83,10 +83,7 @@ public class ImageFormatManager lock (HashLock) { - if (!this.imageFormats.Contains(format)) - { - this.imageFormats.Add(format); - } + this.imageFormats.Add(format); } } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d8305a3f57..4e8067016e 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1938,8 +1938,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals // Keywords should not be empty or have leading or trailing whitespace. name = PngConstants.Encoding.GetString(keywordBytes); return !string.IsNullOrWhiteSpace(name) - && !name.StartsWith(" ", StringComparison.Ordinal) - && !name.EndsWith(" ", StringComparison.Ordinal); + && !name.StartsWith(' ') && !name.EndsWith(' '); } private static bool IsXmpTextData(ReadOnlySpan keywordBytes) From 8b2e164c83a7fc910a6f84c686f8dc12e1350291 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 20 Nov 2023 08:17:54 +0100 Subject: [PATCH 042/219] Fix CA1857 --- src/ImageSharp.ruleset | 1 - src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs | 5 +++-- src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index 11f5041589..8327dd7565 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -2,7 +2,6 @@ - diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 7caaa5868d..373069e9bc 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -58,7 +59,7 @@ internal static partial class SimdUtils public static void Shuffle4Reduce( ref ReadOnlySpan source, ref Span dest, - byte control) + [ConstantExpected] byte control) { if (Avx.IsSupported || Sse.IsSupported) { @@ -217,7 +218,7 @@ internal static partial class SimdUtils private static void Shuffle4( ReadOnlySpan source, Span dest, - byte control) + [ConstantExpected] byte control) { if (Avx.IsSupported) { diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs index c1437c05e6..83cd3d246c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -20,7 +21,7 @@ internal static partial class SimdUtils public static void Shuffle4( ReadOnlySpan source, Span dest, - byte control) + [ConstantExpected] byte control) { VerifyShuffle4SpanInput(source, dest); From 958c9c9b10a8ca0fbc7b39c1a470a820d8941305 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 21 Nov 2023 21:16:57 +1000 Subject: [PATCH 043/219] Deduper works --- src/ImageSharp/Formats/AnimationUtilities.cs | 157 ++++++ src/ImageSharp/Formats/Gif/GifEncoder.cs | 2 - src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 479 ++++-------------- src/ImageSharp/Formats/Gif/LzwEncoder.cs | 12 +- .../Processors/Dithering/ErrorDither.cs | 14 +- .../Quantization/EuclideanPixelMap{TPixel}.cs | 79 +-- .../Quantization/QuantizerUtilities.cs | 4 +- .../Formats/Gif/GifEncoderTests.cs | 18 +- tests/ImageSharp.Tests/TestImages.cs | 20 +- tests/Images/Input/Gif/mixed-disposal.gif | 3 + 10 files changed, 363 insertions(+), 425 deletions(-) create mode 100644 src/ImageSharp/Formats/AnimationUtilities.cs create mode 100644 tests/Images/Input/Gif/mixed-disposal.gif diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs new file mode 100644 index 0000000000..1bca34eae4 --- /dev/null +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -0,0 +1,157 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Advanced; +using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats; + +/// +/// Utility methods for animated formats. +/// +internal static class AnimationUtilities +{ + /// + /// Deduplicates pixels between the previous and current frame returning only the changed pixels and bounds. + /// + /// The type of pixel format. + /// The configuration. + /// The previous frame if present. + /// The current frame. + /// The resultant output. + /// The value to use when replacing duplicate pixels. + /// The representing the operation result. + public static (bool Difference, Rectangle Bounds) DeDuplicatePixels( + Configuration configuration, + ImageFrame? previousFrame, + ImageFrame currentFrame, + ImageFrame resultFrame, + Vector4 replacement) + where TPixel : unmanaged, IPixel + { + MemoryAllocator memoryAllocator = configuration.MemoryAllocator; + IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 3, AllocationOptions.Clean); + Span previous = buffers.GetSpan()[..currentFrame.Width]; + Span current = buffers.GetSpan().Slice(currentFrame.Width, currentFrame.Width); + Span result = buffers.GetSpan()[(currentFrame.Width * 2)..]; + + int top = int.MinValue; + int bottom = int.MaxValue; + int left = int.MaxValue; + int right = int.MinValue; + + bool hasDiff = false; + for (int y = 0; y < currentFrame.Height; y++) + { + if (previousFrame != null) + { + PixelOperations.Instance.ToVector4(configuration, previousFrame.DangerousGetPixelRowMemory(y).Span, previous, PixelConversionModifiers.Scale); + } + + PixelOperations.Instance.ToVector4(configuration, currentFrame.DangerousGetPixelRowMemory(y).Span, current, PixelConversionModifiers.Scale); + + ref Vector256 previousBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(previous)); + ref Vector256 currentBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(current)); + ref Vector256 resultBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); + + Vector256 replacement256 = Vector256.Create(replacement.X, replacement.Y, replacement.Z, replacement.W, replacement.X, replacement.Y, replacement.Z, replacement.W); + + int size = Unsafe.SizeOf(); + + bool hasRowDiff = false; + int i = 0; + uint x = 0; + int length = current.Length; + int remaining = current.Length; + if (Avx2.IsSupported && remaining >= 2) + { + while (remaining >= 2) + { + Vector256 p = Unsafe.Add(ref previousBase, x); + Vector256 c = Unsafe.Add(ref currentBase, x); + + // Compare the previous and current pixels + Vector256 neq = Avx.CompareEqual(p, c); + Vector256 mask = neq.AsInt32(); + + neq = Avx.Xor(neq, Vector256.AllBitsSet); + int m = Avx2.MoveMask(neq.AsByte()); + if (m != 0) + { + // If is diff is found, the left side is marked by the min of previously found left side and the diff position. + // The right is the max of the previously found right side and the diff position + 1. + int diff = (int)(i + (uint)(BitOperations.TrailingZeroCount(m) / size)); + left = Math.Min(left, diff); + right = Math.Max(right, diff + 1); + hasRowDiff = true; + hasDiff = true; + } + + // Capture the original alpha values. + mask = Avx2.HorizontalAdd(mask, mask); + mask = Avx2.HorizontalAdd(mask, mask); + mask = Avx2.CompareEqual(mask, Vector256.Create(-4)); + + Vector256 r = Avx.BlendVariable(c, replacement256, mask.AsSingle()); + Unsafe.Add(ref resultBase, x) = r; + + x++; + i += 2; + remaining -= 2; + } + } + + for (i = remaining; i > 0; i--) + { + x = (uint)(length - i); + + Vector4 p = Unsafe.Add(ref Unsafe.As, Vector4>(ref previousBase), x); + Vector4 c = Unsafe.Add(ref Unsafe.As, Vector4>(ref currentBase), x); + ref Vector4 r = ref Unsafe.Add(ref Unsafe.As, Vector4>(ref resultBase), x); + + if (p != c) + { + r = c; + + // If is diff is found, the left side is marked by the min of previously found left side and the diff position. + // The right is the max of the previously found right side and the diff position + 1. + left = Math.Min(left, (int)x); + right = Math.Max(right, (int)x + 1); + hasRowDiff = true; + hasDiff = true; + } + else + { + r = replacement; + } + } + + if (hasRowDiff) + { + if (top == int.MinValue) + { + top = y; + } + + bottom = y + 1; + } + + PixelOperations.Instance.FromVector4Destructive(configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span, PixelConversionModifiers.Scale); + } + + Rectangle bounds = Rectangle.FromLTRB( + left = Numerics.Clamp(left, 0, resultFrame.Width - 1), + top = Numerics.Clamp(top, 0, resultFrame.Height - 1), + Numerics.Clamp(right, left + 1, resultFrame.Width), + Numerics.Clamp(bottom, top + 1, resultFrame.Height)); + + return new(hasDiff, bounds); + } +} diff --git a/src/ImageSharp/Formats/Gif/GifEncoder.cs b/src/ImageSharp/Formats/Gif/GifEncoder.cs index 150ee9ccf0..ab05548ac5 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoder.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoder.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; - namespace SixLabors.ImageSharp.Formats.Gif; /// diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index d22b960ec6..2bc3e53f78 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -4,9 +4,6 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; @@ -97,8 +94,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // Work out if there is an explicit transparent index set for the frame. We use that to ensure the // correct value is set for the background index when quantizing. - GifFrameMetadata? frameMetadata = GetGifFrameMetadata(image.Frames.RootFrame, -1); - int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); + GifFrameMetadata frameMetadata = GetGifFrameMetadata(image.Frames.RootFrame, -1); if (this.quantizer is null) { @@ -106,6 +102,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals if (gifMetadata.ColorTableMode == GifColorTableMode.Global && gifMetadata.GlobalColorTable?.Length > 0) { // We avoid dithering by default to preserve the original colors. + int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex); } else @@ -132,13 +129,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals WriteHeader(stream); // Write the LSD. - transparencyIndex = GetTransparentIndex(quantized, frameMetadata); - byte backgroundIndex = unchecked((byte)transparencyIndex); - if (transparencyIndex == -1) + int derivedTransparencyIndex = GetTransparentIndex(quantized, null); + if (derivedTransparencyIndex >= 0) { - backgroundIndex = gifMetadata.BackgroundColorIndex; + frameMetadata.HasTransparency = true; + frameMetadata.TransparencyIndex = ClampIndex(derivedTransparencyIndex); } + byte backgroundIndex = derivedTransparencyIndex >= 0 + ? frameMetadata.TransparencyIndex + : gifMetadata.BackgroundColorIndex; + // Get the number of bits. int bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.WriteLogicalScreenDescriptor(image.Metadata, image.Width, image.Height, backgroundIndex, useGlobalTable, bitDepth, stream); @@ -158,16 +159,16 @@ internal sealed class GifEncoderCore : IImageEncoderInternals this.WriteApplicationExtensions(stream, image.Frames.Count, gifMetadata.RepeatCount, xmpProfile); } - this.EncodeFirstFrame(stream, frameMetadata, quantized, transparencyIndex); + this.EncodeFirstFrame(stream, frameMetadata, quantized); // Capture the global palette for reuse on subsequent frames and cleanup the quantized frame. TPixel[] globalPalette = image.Frames.Count == 1 ? Array.Empty() : quantized.Palette.ToArray(); - quantized.Dispose(); - - this.EncodeAdditionalFrames(stream, image, globalPalette, transparencyIndex); + this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMethod); stream.WriteByte(GifConstants.EndIntroducer); + + quantized.Dispose(); } private static GifMetadata GetGifMetadata(Image image) @@ -194,12 +195,12 @@ internal sealed class GifEncoderCore : IImageEncoderInternals return new(); } - private static GifFrameMetadata? GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) + private static GifFrameMetadata GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) where TPixel : unmanaged, IPixel { if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) { - return gif; + return (GifFrameMetadata)gif.DeepClone(); } GifFrameMetadata? metadata = null; @@ -218,17 +219,18 @@ internal sealed class GifEncoderCore : IImageEncoderInternals if (metadata?.ColorTableMode == GifColorTableMode.Global && transparencyIndex > -1) { metadata.HasTransparency = true; - metadata.TransparencyIndex = unchecked((byte)transparencyIndex); + metadata.TransparencyIndex = ClampIndex(transparencyIndex); } - return metadata; + return metadata ?? new(); } private void EncodeAdditionalFrames( Stream stream, Image image, ReadOnlyMemory globalPalette, - int globalTransparencyIndex) + int globalTransparencyIndex, + GifDisposalMethod previousDisposalMethod) where TPixel : unmanaged, IPixel { if (image.Frames.Count == 1) @@ -251,15 +253,15 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { // Gather the metadata for this frame. ImageFrame currentFrame = image.Frames[i]; - GifFrameMetadata? gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex); - bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata?.ColorTableMode == GifColorTableMode.Local); + GifFrameMetadata gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex); + bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata.ColorTableMode == GifColorTableMode.Local); if (!useLocal && !hasPaletteQuantizer && i > 0) { // The palette quantizer can reuse the same global pixel map across multiple frames since the palette is unchanging. // This allows a reduction of memory usage across multi-frame gifs using a global palette // and also allows use to reuse the cache from previous runs. - int transparencyIndex = gifMetadata?.HasTransparency == true ? gifMetadata.TransparencyIndex : -1; + int transparencyIndex = gifMetadata.HasTransparency ? gifMetadata.TransparencyIndex : -1; paletteQuantizer = new(this.configuration, this.quantizer!.Options, globalPalette, transparencyIndex); hasPaletteQuantizer = true; } @@ -271,9 +273,11 @@ internal sealed class GifEncoderCore : IImageEncoderInternals encodingFrame, useLocal, gifMetadata, - paletteQuantizer); + paletteQuantizer, + previousDisposalMethod); previousFrame = currentFrame; + previousDisposalMethod = gifMetadata.DisposalMethod; } if (hasPaletteQuantizer) @@ -284,16 +288,15 @@ internal sealed class GifEncoderCore : IImageEncoderInternals private void EncodeFirstFrame( Stream stream, - GifFrameMetadata? metadata, - IndexedImageFrame quantized, - int transparencyIndex) + GifFrameMetadata metadata, + IndexedImageFrame quantized) where TPixel : unmanaged, IPixel { - this.WriteGraphicalControlExtension(metadata, transparencyIndex, stream); + this.WriteGraphicalControlExtension(metadata, stream); Buffer2D indices = ((IPixelSource)quantized).PixelBuffer; Rectangle interest = indices.FullRectangle(); - bool useLocal = this.colorTableMode == GifColorTableMode.Local || (metadata?.ColorTableMode == GifColorTableMode.Local); + bool useLocal = this.colorTableMode == GifColorTableMode.Local || (metadata.ColorTableMode == GifColorTableMode.Local); int bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); this.WriteImageDescriptor(interest, useLocal, bitDepth, stream); @@ -303,7 +306,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals this.WriteColorTable(quantized, bitDepth, stream); } - this.WriteImageData(indices, interest, stream, quantized.Palette.Length, transparencyIndex); + this.WriteImageData(indices, stream, quantized.Palette.Length, metadata.TransparencyIndex); } private void EncodeAdditionalFrame( @@ -312,371 +315,121 @@ internal sealed class GifEncoderCore : IImageEncoderInternals ImageFrame currentFrame, ImageFrame encodingFrame, bool useLocal, - GifFrameMetadata? metadata, - PaletteQuantizer globalPaletteQuantizer) + GifFrameMetadata metadata, + PaletteQuantizer globalPaletteQuantizer, + GifDisposalMethod previousDisposal) where TPixel : unmanaged, IPixel { // Capture any explicit transparency index from the metadata. // We use it to determine the value to use to replace duplicate pixels. - int transparencyIndex = metadata?.HasTransparency == true ? metadata.TransparencyIndex : -1; - Vector4 replacement = Vector4.Zero; - if (transparencyIndex >= 0) - { - if (useLocal) - { - if (metadata?.LocalColorTable?.Length > 0) - { - ReadOnlySpan palette = metadata.LocalColorTable.Value.Span; - if (transparencyIndex < palette.Length) - { - replacement = palette[transparencyIndex].ToScaledVector4(); - } - } - } - else - { - ReadOnlySpan palette = globalPaletteQuantizer.Palette.Span; - if (transparencyIndex < palette.Length) - { - replacement = palette[transparencyIndex].ToScaledVector4(); - } - } - } + int transparencyIndex = metadata.HasTransparency ? metadata.TransparencyIndex : -1; - // We can't deduplicate here as we need the background pixels to be present in the buffer. - if (metadata?.DisposalMethod == GifDisposalMethod.RestoreToBackground) - { - for (int y = 0; y < currentFrame.PixelBuffer.Height; y++) - { - Span sourceRow = currentFrame.PixelBuffer.DangerousGetRowSpan(y); - Span destinationRow = encodingFrame.PixelBuffer.DangerousGetRowSpan(y); - sourceRow.CopyTo(destinationRow); - } - } - else - { - this.DeDuplicatePixels(previousFrame, currentFrame, encodingFrame, replacement); - } + ImageFrame? previous = previousDisposal == GifDisposalMethod.RestoreToBackground ? null : previousFrame; - IndexedImageFrame quantized; - if (useLocal) - { - // Reassign using the current frame and details. - if (metadata?.LocalColorTable?.Length > 0) - { - // We can use the color data from the decoded metadata here. - // We avoid dithering by default to preserve the original colors. - ReadOnlyMemory palette = metadata.LocalColorTable.Value; - PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); - using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); - quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, encodingFrame.Bounds()); - } - else - { - // We must quantize the frame to generate a local color table. - IQuantizer quantizer = this.hasQuantizer ? this.quantizer! : KnownQuantizers.Octree; - using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); - quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, encodingFrame.Bounds()); - } - } - else - { - // Quantize the image using the global palette. - // Individual frames, though using the shared palette, can use a different transparent index to represent transparency. - globalPaletteQuantizer.SetTransparentIndex(transparencyIndex); - quantized = globalPaletteQuantizer.QuantizeFrame(encodingFrame, encodingFrame.Bounds()); - } + // Deduplicate and quantize the frame capturing only required parts. + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(this.configuration, previous, currentFrame, encodingFrame, Vector4.Zero); - // Recalculate the transparency index as depending on the quantizer used could have a new value. - transparencyIndex = GetTransparentIndex(quantized, metadata); - - // Trim down the buffer to the minimum size required. - Buffer2D indices = ((IPixelSource)quantized).PixelBuffer; - Rectangle interest = TrimTransparentPixels(indices, transparencyIndex); + using IndexedImageFrame quantized = this.QuantizeAdditionalFrameAndUpdateMetadata( + encodingFrame, + bounds, + metadata, + useLocal, + globalPaletteQuantizer, + difference, + transparencyIndex); - this.WriteGraphicalControlExtension(metadata, transparencyIndex, stream); + this.WriteGraphicalControlExtension(metadata, stream); int bitDepth = ColorNumerics.GetBitsNeededForColorDepth(quantized.Palette.Length); - this.WriteImageDescriptor(interest, useLocal, bitDepth, stream); + this.WriteImageDescriptor(bounds, useLocal, bitDepth, stream); if (useLocal) { this.WriteColorTable(quantized, bitDepth, stream); } - this.WriteImageData(indices, interest, stream, quantized.Palette.Length, transparencyIndex); + Buffer2D indices = ((IPixelSource)quantized).PixelBuffer; + this.WriteImageData(indices, stream, quantized.Palette.Length, metadata.TransparencyIndex); } - private void DeDuplicatePixels( - ImageFrame backgroundFrame, - ImageFrame sourceFrame, - ImageFrame resultFrame, - Vector4 replacement) + private IndexedImageFrame QuantizeAdditionalFrameAndUpdateMetadata( + ImageFrame encodingFrame, + Rectangle bounds, + GifFrameMetadata metadata, + bool useLocal, + PaletteQuantizer globalPaletteQuantizer, + bool hasDuplicates, + int transparencyIndex) where TPixel : unmanaged, IPixel { - IMemoryOwner buffers = this.memoryAllocator.Allocate(backgroundFrame.Width * 3); - Span background = buffers.GetSpan()[..backgroundFrame.Width]; - Span source = buffers.GetSpan()[backgroundFrame.Width..]; - Span result = buffers.GetSpan()[(backgroundFrame.Width * 2)..]; - - // TODO: This algorithm is greedy and will always replace matching colors, however, theoretically, if the proceeding color - // is the same, but not replaced, you would actually be better of not replacing it since longer runs compress better. - // This would require a more complex algorithm. - for (int y = 0; y < backgroundFrame.Height; y++) - { - PixelOperations.Instance.ToVector4(this.configuration, backgroundFrame.DangerousGetPixelRowMemory(y).Span, background, PixelConversionModifiers.Scale); - PixelOperations.Instance.ToVector4(this.configuration, sourceFrame.DangerousGetPixelRowMemory(y).Span, source, PixelConversionModifiers.Scale); - - ref Vector256 backgroundBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(background)); - ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector256 resultBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - - uint x = 0; - int remaining = background.Length; - if (Avx2.IsSupported && remaining >= 2) - { - Vector256 replacement256 = Vector256.Create(replacement.X, replacement.Y, replacement.Z, replacement.W, replacement.X, replacement.Y, replacement.Z, replacement.W); - - while (remaining >= 2) - { - Vector256 b = Unsafe.Add(ref backgroundBase, x); - Vector256 s = Unsafe.Add(ref sourceBase, x); - - Vector256 m = Avx.CompareEqual(b, s).AsInt32(); - - m = Avx2.HorizontalAdd(m, m); - m = Avx2.HorizontalAdd(m, m); - m = Avx2.CompareEqual(m, Vector256.Create(-4)); - - Unsafe.Add(ref resultBase, x) = Avx.BlendVariable(s, replacement256, m.AsSingle()); - - x++; - remaining -= 2; - } - } - - for (int i = remaining; i >= 0; i--) - { - x = (uint)i; - Vector4 b = Unsafe.Add(ref Unsafe.As, Vector4>(ref backgroundBase), x); - Vector4 s = Unsafe.Add(ref Unsafe.As, Vector4>(ref sourceBase), x); - ref Vector4 r = ref Unsafe.Add(ref Unsafe.As, Vector4>(ref resultBase), x); - r = (b == s) ? replacement : s; - } - - PixelOperations.Instance.FromVector4Destructive(this.configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span, PixelConversionModifiers.Scale); - } - } - - private static Rectangle TrimTransparentPixels(Buffer2D buffer, int transparencyIndex) - { - if (transparencyIndex < 0) - { - return buffer.FullRectangle(); - } - - byte trimmableIndex = unchecked((byte)transparencyIndex); - - int top = int.MinValue; - int bottom = int.MaxValue; - int left = int.MaxValue; - int right = int.MinValue; - int minY = -1; - bool isTransparentRow = true; - - // Run through the buffer in a single pass. Use variables to track the min/max values. - for (int y = 0; y < buffer.Height; y++) + IndexedImageFrame quantized; + if (useLocal) { - isTransparentRow = true; - Span rowSpan = buffer.DangerousGetRowSpan(y); - ref byte rowPtr = ref MemoryMarshal.GetReference(rowSpan); - nint rowLength = (nint)(uint)rowSpan.Length; - nint x = 0; - -#if NET7_0_OR_GREATER - if (Vector128.IsHardwareAccelerated && rowLength >= Vector128.Count) - { - Vector256 trimmableVec256 = Vector256.Create(trimmableIndex); - - if (Vector256.IsHardwareAccelerated && rowLength >= Vector256.Count) - { - do - { - Vector256 vec = Vector256.LoadUnsafe(ref rowPtr, (nuint)x); - Vector256 notEquals = ~Vector256.Equals(vec, trimmableVec256); - uint mask = notEquals.ExtractMostSignificantBits(); - - if (mask != 0) - { - isTransparentRow = false; - nint start = x + (nint)uint.TrailingZeroCount(mask); - nint end = (nint)uint.LeadingZeroCount(mask); - - // end is from the end, but we need the index from the beginning - end = x + Vector256.Count - 1 - end; - - left = Math.Min(left, (int)start); - right = Math.Max(right, (int)end); - } - - x += Vector256.Count; - } - while (x <= rowLength - Vector256.Count); - } - - Vector128 trimmableVec = Vector256.IsHardwareAccelerated - ? trimmableVec256.GetLower() - : Vector128.Create(trimmableIndex); - - while (x <= rowLength - Vector128.Count) - { - Vector128 vec = Vector128.LoadUnsafe(ref rowPtr, (nuint)x); - Vector128 notEquals = ~Vector128.Equals(vec, trimmableVec); - uint mask = notEquals.ExtractMostSignificantBits(); - - if (mask != 0) - { - isTransparentRow = false; - nint start = x + (nint)uint.TrailingZeroCount(mask); - nint end = (nint)uint.LeadingZeroCount(mask) - Vector128.Count; - - // end is from the end, but we need the index from the beginning - end = x + Vector128.Count - 1 - end; - - left = Math.Min(left, (int)start); - right = Math.Max(right, (int)end); - } - - x += Vector128.Count; - } - } -#else - if (Sse41.IsSupported && rowLength >= Vector128.Count) + // Reassign using the current frame and details. + if (metadata.LocalColorTable?.Length > 0) { - Vector256 trimmableVec256 = Vector256.Create(trimmableIndex); + // We can use the color data from the decoded metadata here. + // We avoid dithering by default to preserve the original colors. + ReadOnlyMemory palette = metadata.LocalColorTable.Value; - if (Avx2.IsSupported && rowLength >= Vector256.Count) + if (hasDuplicates && !metadata.HasTransparency) { - do - { - Vector256 vec = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rowPtr, x)); - Vector256 notEquals = Avx2.CompareEqual(vec, trimmableVec256); - notEquals = Avx2.Xor(notEquals, Vector256.AllBitsSet); - int mask = Avx2.MoveMask(notEquals); - - if (mask != 0) - { - isTransparentRow = false; - nint start = x + (nint)(uint)BitOperations.TrailingZeroCount(mask); - nint end = (nint)(uint)BitOperations.LeadingZeroCount((uint)mask); - - // end is from the end, but we need the index from the beginning - end = x + Vector256.Count - 1 - end; - - left = Math.Min(left, (int)start); - right = Math.Max(right, (int)end); - } - - x += Vector256.Count; - } - while (x <= rowLength - Vector256.Count); + // A difference was captured but the metadata does not have transparency. + metadata.HasTransparency = true; + transparencyIndex = palette.Length; + metadata.TransparencyIndex = ClampIndex(transparencyIndex); } - Vector128 trimmableVec = Sse41.IsSupported - ? trimmableVec256.GetLower() - : Vector128.Create(trimmableIndex); - - while (x <= rowLength - Vector128.Count) - { - Vector128 vec = Unsafe.ReadUnaligned>(ref Unsafe.Add(ref rowPtr, x)); - Vector128 notEquals = Sse2.CompareEqual(vec, trimmableVec); - notEquals = Sse2.Xor(notEquals, Vector128.AllBitsSet); - int mask = Sse2.MoveMask(notEquals); - - if (mask != 0) - { - isTransparentRow = false; - nint start = x + (nint)(uint)BitOperations.TrailingZeroCount(mask); - nint end = (nint)(uint)BitOperations.LeadingZeroCount((uint)mask) - Vector128.Count; - - // end is from the end, but we need the index from the beginning - end = x + Vector128.Count - 1 - end; - - left = Math.Min(left, (int)start); - right = Math.Max(right, (int)end); - } - - x += Vector128.Count; - } + PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); } -#endif - for (; x < rowLength; ++x) + else { - if (Unsafe.Add(ref rowPtr, x) != trimmableIndex) - { - isTransparentRow = false; - left = Math.Min(left, (int)x); - right = Math.Max(right, (int)x); - } - } + // We must quantize the frame to generate a local color table. + IQuantizer quantizer = this.hasQuantizer ? this.quantizer! : KnownQuantizers.Octree; + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); - if (!isTransparentRow) - { - if (y == 0) + // The transparency index derived by the quantizer might differ from the index + // within the metadata. We need to update the metadata to reflect this. + int derivedTransparencyIndex = GetTransparentIndex(quantized, null); + if (derivedTransparencyIndex < 0) { - // First row is opaque. - // Capture to prevent over assignment when a match is found below. - top = 0; + // If no index is found set to the palette length, this trick allows us to fake transparency without an explicit index. + derivedTransparencyIndex = quantized.Palette.Length; } - // The minimum top bounds have already been captured. - // Increment the bottom to include the current opaque row. - if (minY < 0 && top != 0) - { - // Increment to the first opaque row. - top++; - } + metadata.TransparencyIndex = ClampIndex(derivedTransparencyIndex); - minY = top; - bottom = y; - } - else - { - // We've yet to hit an opaque row. Capture the top position. - if (minY < 0) + if (hasDuplicates) { - top = Math.Max(top, y); + metadata.HasTransparency = true; } - - bottom = Math.Min(bottom, y); } } - - if (left == int.MaxValue) - { - left = 0; - } - - if (right == int.MinValue) + else { - right = buffer.Width; - } + // Quantize the image using the global palette. + // Individual frames, though using the shared palette, can use a different transparent index to represent transparency. - if (top == bottom || left == right) - { - // The entire image is transparent. - return buffer.FullRectangle(); - } + // A difference was captured but the metadata does not have transparency. + if (hasDuplicates && !metadata.HasTransparency) + { + metadata.HasTransparency = true; + transparencyIndex = globalPaletteQuantizer.Palette.Length; + metadata.TransparencyIndex = ClampIndex(transparencyIndex); + } - if (!isTransparentRow) - { - // Last row is opaque. - bottom = buffer.Height; + globalPaletteQuantizer.SetTransparentIndex(transparencyIndex); + quantized = globalPaletteQuantizer.QuantizeFrame(encodingFrame, bounds); } - return Rectangle.FromLTRB(left, top, Math.Min(right + 1, buffer.Width), Math.Min(bottom + 1, buffer.Height)); + return quantized; } + private static byte ClampIndex(int value) => (byte)Numerics.Clamp(value, byte.MinValue, byte.MaxValue); + /// /// Returns the index of the most transparent color in the palette. /// @@ -868,30 +621,19 @@ internal sealed class GifEncoderCore : IImageEncoderInternals /// Writes the optional graphics control extension to the stream. /// /// The metadata of the image or frame. - /// The index of the color in the color palette to make transparent. /// The stream to write to. - private void WriteGraphicalControlExtension(GifFrameMetadata? metadata, int transparencyIndex, Stream stream) + private void WriteGraphicalControlExtension(GifFrameMetadata metadata, Stream stream) { - GifFrameMetadata? data = metadata; - bool hasTransparency; - if (metadata is null) - { - data = new(); - hasTransparency = transparencyIndex >= 0; - } - else - { - hasTransparency = metadata.HasTransparency; - } + bool hasTransparency = metadata.HasTransparency; byte packedValue = GifGraphicControlExtension.GetPackedValue( - disposalMethod: data!.DisposalMethod, + disposalMethod: metadata.DisposalMethod, transparencyFlag: hasTransparency); GifGraphicControlExtension extension = new( packed: packedValue, - delayTime: (ushort)data.FrameDelay, - transparencyIndex: hasTransparency ? unchecked((byte)transparencyIndex) : byte.MinValue); + delayTime: (ushort)metadata.FrameDelay, + transparencyIndex: hasTransparency ? metadata.TransparencyIndex : byte.MinValue); this.WriteExtension(extension, stream); } @@ -992,14 +734,11 @@ internal sealed class GifEncoderCore : IImageEncoderInternals /// Writes the image pixel data to the stream. /// /// The containing indexed pixels. - /// The region of interest. /// The stream to write to. /// The length of the frame color palette. /// The index of the color used to represent transparency. - private void WriteImageData(Buffer2D indices, Rectangle interest, Stream stream, int paletteLength, int transparencyIndex) + private void WriteImageData(Buffer2D indices, Stream stream, int paletteLength, int transparencyIndex) { - Buffer2DRegion region = indices.GetRegion(interest); - // Pad the bit depth when required for encoding the image data. // This is a common trick which allows to use out of range indexes for transparency and avoid allocating a larger color palette // as decoders skip indexes that are out of range. @@ -1008,6 +747,6 @@ internal sealed class GifEncoderCore : IImageEncoderInternals : 0; using LzwEncoder encoder = new(this.memoryAllocator, ColorNumerics.GetBitsNeededForColorDepth(paletteLength + padding)); - encoder.Encode(region, stream); + encoder.Encode(indices, stream); } } diff --git a/src/ImageSharp/Formats/Gif/LzwEncoder.cs b/src/ImageSharp/Formats/Gif/LzwEncoder.cs index 4b40c44e45..d4050810df 100644 --- a/src/ImageSharp/Formats/Gif/LzwEncoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwEncoder.cs @@ -186,7 +186,7 @@ internal sealed class LzwEncoder : IDisposable /// /// The 2D buffer of indexed pixels. /// The stream to write to. - public void Encode(Buffer2DRegion indexedPixels, Stream stream) + public void Encode(Buffer2D indexedPixels, Stream stream) { // Write "initial code size" byte stream.WriteByte((byte)this.initialCodeSize); @@ -204,7 +204,7 @@ internal sealed class LzwEncoder : IDisposable /// The number of bits /// See [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static int GetMaxcode(int bitCount) => (1 << bitCount) - 1; + private static int GetMaxCode(int bitCount) => (1 << bitCount) - 1; /// /// Add a character to the end of the current packet, and if it is 254 characters, @@ -249,7 +249,7 @@ internal sealed class LzwEncoder : IDisposable /// The 2D buffer of indexed pixels. /// The initial bits. /// The stream to write to. - private void Compress(Buffer2DRegion indexedPixels, int initialBits, Stream stream) + private void Compress(Buffer2D indexedPixels, int initialBits, Stream stream) { // Set up the globals: globalInitialBits - initial number of bits this.globalInitialBits = initialBits; @@ -257,7 +257,7 @@ internal sealed class LzwEncoder : IDisposable // Set up the necessary values this.clearFlag = false; this.bitCount = this.globalInitialBits; - this.maxCode = GetMaxcode(this.bitCount); + this.maxCode = GetMaxCode(this.bitCount); this.clearCode = 1 << (initialBits - 1); this.eofCode = this.clearCode + 1; this.freeEntry = this.clearCode + 2; @@ -383,7 +383,7 @@ internal sealed class LzwEncoder : IDisposable { if (this.clearFlag) { - this.maxCode = GetMaxcode(this.bitCount = this.globalInitialBits); + this.maxCode = GetMaxCode(this.bitCount = this.globalInitialBits); this.clearFlag = false; } else @@ -391,7 +391,7 @@ internal sealed class LzwEncoder : IDisposable ++this.bitCount; this.maxCode = this.bitCount == MaxBits ? MaxMaxCode - : GetMaxcode(this.bitCount); + : GetMaxCode(this.bitCount); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index 754aac90ea..3c56d0243b 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -107,15 +107,15 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I float scale = quantizer.Options.DitherScale; Buffer2D sourceBuffer = source.PixelBuffer; - for (int y = bounds.Top; y < bounds.Bottom; y++) + for (int y = 0; y < destination.Height; y++) { - ref TPixel sourceRowRef = ref MemoryMarshal.GetReference(sourceBuffer.DangerousGetRowSpan(y)); - ref byte destinationRowRef = ref MemoryMarshal.GetReference(destination.GetWritablePixelRowSpanUnsafe(y - offsetY)); + ReadOnlySpan sourceRow = sourceBuffer.DangerousGetRowSpan(y + offsetY); + Span destinationRow = destination.GetWritablePixelRowSpanUnsafe(y); - for (int x = bounds.Left; x < bounds.Right; x++) + for (int x = 0; x < destinationRow.Length; x++) { - TPixel sourcePixel = Unsafe.Add(ref sourceRowRef, (uint)x); - Unsafe.Add(ref destinationRowRef, (uint)(x - offsetX)) = quantizer.GetQuantizedColor(sourcePixel, out TPixel transformed); + TPixel sourcePixel = sourceRow[x + offsetX]; + destinationRow[x] = quantizer.GetQuantizedColor(sourcePixel, out TPixel transformed); this.Dither(source, bounds, sourcePixel, transformed, x, y, scale); } } @@ -200,7 +200,7 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I } ref TPixel pixel = ref rowSpan[targetX]; - var result = pixel.ToVector4(); + Vector4 result = pixel.ToVector4(); result += error * coefficient; pixel.FromVector4(result); diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 8aa166d16c..3c7d576709 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; @@ -23,6 +22,7 @@ internal sealed class EuclideanPixelMap : IDisposable { private Rgba32[] rgbaPalette; private int transparentIndex; + private readonly TPixel transparentMatch; /// /// Do not make this readonly! Struct value would be always copied on non-readonly method calls. @@ -54,8 +54,9 @@ internal sealed class EuclideanPixelMap : IDisposable this.cache = new ColorDistanceCache(configuration.MemoryAllocator); PixelOperations.Instance.ToRgba32(configuration, this.Palette.Span, this.rgbaPalette); - // If the provided transparentIndex is outside of the palette, silently ignore it. - this.transparentIndex = transparentIndex < this.Palette.Length ? transparentIndex : -1; + this.transparentIndex = transparentIndex; + Unsafe.SkipInit(out this.transparentMatch); + this.transparentMatch.FromRgba32(default); } /// @@ -97,32 +98,40 @@ internal sealed class EuclideanPixelMap : IDisposable this.Palette = palette; this.rgbaPalette = new Rgba32[palette.Length]; PixelOperations.Instance.ToRgba32(this.configuration, this.Palette.Span, this.rgbaPalette); + this.transparentIndex = -1; this.cache.Clear(); } /// - /// Allows setting the transparent index after construction. If the provided transparentIndex is outside of the palette, silently ignore it. + /// Allows setting the transparent index after construction. /// /// An explicit index at which to match transparent pixels. - public void SetTransparentIndex(int index) => this.transparentIndex = index < this.Palette.Length ? index : -1; + public void SetTransparentIndex(int index) + { + if (index != this.transparentIndex) + { + this.cache.Clear(); + } + + this.transparentIndex = index; + } [MethodImpl(InliningOptions.ShortMethod)] private int GetClosestColorSlow(Rgba32 rgba, ref TPixel paletteRef, out TPixel match) { // Loop through the palette and find the nearest match. int index = 0; - float leastDistance = float.MaxValue; if (this.transparentIndex >= 0 && rgba == default) { // We have explicit instructions. No need to search. index = this.transparentIndex; - DebugGuard.MustBeLessThan(index, this.Palette.Length, nameof(index)); this.cache.Add(rgba, (byte)index); - match = Unsafe.Add(ref paletteRef, (uint)index); + match = this.transparentMatch; return index; } + float leastDistance = float.MaxValue; for (int i = 0; i < this.rgbaPalette.Length; i++) { Rgba32 candidate = this.rgbaPalette[i]; @@ -175,18 +184,24 @@ internal sealed class EuclideanPixelMap : IDisposable /// The granularity of the cache has been determined based upon the current /// suite of test images and provides the lowest possible memory usage while /// providing enough match accuracy. - /// Entry count is currently limited to 2335905 entries (4671810 bytes ~4.45MB). + /// Entry count is currently limited to 4601025 entries (8MB). /// /// private unsafe struct ColorDistanceCache : IDisposable { - private const int IndexBits = 5; - private const int IndexAlphaBits = 6; - private const int IndexCount = (1 << IndexBits) + 1; - private const int IndexAlphaCount = (1 << IndexAlphaBits) + 1; - private const int RgbShift = 8 - IndexBits; - private const int AlphaShift = 8 - IndexAlphaBits; - private const int Entries = IndexCount * IndexCount * IndexCount * IndexAlphaCount; + private const int IndexRBits = 5; + private const int IndexGBits = 5; + private const int IndexBBits = 6; + private const int IndexABits = 6; + private const int IndexRCount = (1 << IndexRBits) + 1; + private const int IndexGCount = (1 << IndexGBits) + 1; + private const int IndexBCount = (1 << IndexBBits) + 1; + private const int IndexACount = (1 << IndexABits) + 1; + private const int RShift = 8 - IndexRBits; + private const int GShift = 8 - IndexGBits; + private const int BShift = 8 - IndexBBits; + private const int AShift = 8 - IndexABits; + private const int Entries = IndexRCount * IndexGCount * IndexBCount * IndexACount; private MemoryHandle tableHandle; private readonly IMemoryOwner table; private readonly short* tablePointer; @@ -202,22 +217,14 @@ internal sealed class EuclideanPixelMap : IDisposable [MethodImpl(InliningOptions.ShortMethod)] public readonly void Add(Rgba32 rgba, byte index) { - int r = rgba.R >> RgbShift; - int g = rgba.G >> RgbShift; - int b = rgba.B >> RgbShift; - int a = rgba.A >> AlphaShift; - int idx = GetPaletteIndex(r, g, b, a); + int idx = GetPaletteIndex(rgba); this.tablePointer[idx] = index; } [MethodImpl(InliningOptions.ShortMethod)] public readonly bool TryGetValue(Rgba32 rgba, out short match) { - int r = rgba.R >> RgbShift; - int g = rgba.G >> RgbShift; - int b = rgba.B >> RgbShift; - int a = rgba.A >> AlphaShift; - int idx = GetPaletteIndex(r, g, b, a); + int idx = GetPaletteIndex(rgba); match = this.tablePointer[idx]; return match > -1; } @@ -229,15 +236,17 @@ internal sealed class EuclideanPixelMap : IDisposable public readonly void Clear() => this.table.GetSpan().Fill(-1); [MethodImpl(InliningOptions.ShortMethod)] - private static int GetPaletteIndex(int r, int g, int b, int a) - => (r << ((IndexBits << 1) + IndexAlphaBits)) - + (r << (IndexBits + IndexAlphaBits + 1)) - + (g << (IndexBits + IndexAlphaBits)) - + (r << (IndexBits << 1)) - + (r << (IndexBits + 1)) - + (g << IndexBits) - + ((r + g + b) << IndexAlphaBits) - + r + g + b + a; + private static int GetPaletteIndex(Rgba32 rgba) + { + int rIndex = rgba.R >> RShift; + int gIndex = rgba.G >> GShift; + int bIndex = rgba.B >> BShift; + int aIndex = rgba.A >> AShift; + + return (aIndex * (IndexRCount * IndexGCount * IndexBCount)) + + (rIndex * (IndexGCount * IndexBCount)) + + (gIndex * IndexBCount) + bIndex; + } public void Dispose() { diff --git a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs index a7edec662e..10ffe68dca 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/QuantizerUtilities.cs @@ -156,10 +156,10 @@ public static class QuantizerUtilities for (int y = 0; y < destination.Height; y++) { - Span sourceRow = sourceBuffer.DangerousGetRowSpan(y + offsetY); + ReadOnlySpan sourceRow = sourceBuffer.DangerousGetRowSpan(y + offsetY); Span destinationRow = destination.GetWritablePixelRowSpanUnsafe(y); - for (int x = 0; x < destination.Width; x++) + for (int x = 0; x < destinationRow.Length; x++) { destinationRow[x] = Unsafe.AsRef(quantizer).GetQuantizedColor(sourceRow[x + offsetX], out TPixel _); } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index cd485b5fab..ef04a4fbaf 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -226,8 +226,6 @@ public class GifEncoderTests } Assert.Equal(iMeta.FrameDelay, cMeta.FrameDelay); - Assert.Equal(iMeta.HasTransparency, cMeta.HasTransparency); - Assert.Equal(iMeta.TransparencyIndex, cMeta.TransparencyIndex); } image.Dispose(); @@ -328,6 +326,8 @@ public class GifEncoderTests using Image output = Image.Load(memStream); + image.Save(provider.Utility.GetTestOutputFileName("gif"), new GifEncoder()); + // TODO: Find a better way to compare. // The image has been visually checked but the quantization and frame trimming pattern used in the gif encoder // means we cannot use an exact comparison nor replicate using the quantizing processor. @@ -357,4 +357,18 @@ public class GifEncoderTests } } } + + public static string[] Animated => TestImages.Gif.Animated; + + [Theory]//(Skip = "Enable for visual animated testing")] + [WithFileCollection(nameof(Animated), PixelTypes.Rgba32)] + public void Encode_Animated_VisualTest(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + + //image.DebugSaveMultiFrame(provider); + + provider.Utility.SaveTestOutputFile(image, "gif", new GifEncoder() { ColorTableMode = GifColorTableMode.Local}, "animated"); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6ad93adfbd..5b49e5aba0 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -479,6 +479,7 @@ public static class TestImages public const string Ratio1x4 = "Gif/base_1x4.gif"; public const string LargeComment = "Gif/large_comment.gif"; public const string GlobalQuantizationTest = "Gif/GlobalQuantizationTest.gif"; + public const string MixedDisposal = "Gif/mixed-disposal.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -508,7 +509,24 @@ public static class TestImages public const string Issue2198 = "Gif/issues/issue_2198.gif"; } - public static readonly string[] All = { Rings, Giphy, Cheers, Trans, Kumin, Leo, Ratio4x1, Ratio1x4 }; + public static readonly string[] Animated = + { + Giphy, + Cheers, + Kumin, + Leo, + MixedDisposal, + GlobalQuantizationTest, + Issues.Issue2198, + Issues.Issue2288_A, + Issues.Issue2288_B, + Issues.Issue2288_C, + Issues.Issue2288_D, + Issues.Issue2450_A, + Issues.Issue2450_B, + Issues.BadDescriptorWidth, + Issues.Issue1530 + }; } public static class Tga diff --git a/tests/Images/Input/Gif/mixed-disposal.gif b/tests/Images/Input/Gif/mixed-disposal.gif new file mode 100644 index 0000000000..07ca32e915 --- /dev/null +++ b/tests/Images/Input/Gif/mixed-disposal.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:bd7d4093d6d75aa149418936bac73f66c3d81d9e01252993f321ee792514a47a +size 16636 From 8825a42e12a8d5d1e325ce6952b5755404331ee4 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Tue, 21 Nov 2023 14:50:57 +0100 Subject: [PATCH 044/219] Added CICP profile types --- .../Metadata/Profiles/CICP/CicpProfile.cs | 72 ++++++++++++ .../Profiles/CICP/Enums/CicpColorPrimaries.cs | 86 ++++++++++++++ .../CICP/Enums/CicpMatrixCoefficients.cs | 96 +++++++++++++++ .../CICP/Enums/CicpTransferCharacteristics.cs | 109 ++++++++++++++++++ .../CICP/T-REC-H.273-202107-S!!PDF-E.pdf | Bin 0 -> 2632310 bytes 5 files changed, 363 insertions(+) create mode 100644 src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs create mode 100644 src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs create mode 100644 src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs create mode 100644 src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs create mode 100644 src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf diff --git a/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs new file mode 100644 index 0000000000..5d6e357c47 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; + +/// +/// Represents a CICP profile as per ITU-T H.273 / ISO/IEC 23091-2_2019 providing access to color space information +/// +public sealed class CicpProfile : IDeepCloneable +{ + /// + /// Initializes a new instance of the class. + /// + public CicpProfile() + : this(2, 2, 2, null) + { + } + + /// + /// Initializes a new instance of the class. + /// + /// The color primaries as number according to ITU-T H.273 / ISO/IEC 23091-2_2019. + /// The transfer characteristics as number according to ITU-T H.273 / ISO/IEC 23091-2_2019. + /// The matrix coefficients as number according to ITU-T H.273 / ISO/IEC 23091-2_2019. + /// The full range flag, or null if unknown. + public CicpProfile(byte colorPrimaries, byte transferCharacteristics, byte matrixCoefficients, bool? fullRange) + { + this.ColorPrimaries = Enum.IsDefined(typeof(CicpColorPrimaries), colorPrimaries) ? (CicpColorPrimaries)colorPrimaries : CicpColorPrimaries.Unspecified; + this.TransferCharacteristics = Enum.IsDefined(typeof(CicpTransferCharacteristics), transferCharacteristics) ? (CicpTransferCharacteristics)transferCharacteristics : CicpTransferCharacteristics.Unspecified; + this.MatrixCoefficients = Enum.IsDefined(typeof(CicpMatrixCoefficients), matrixCoefficients) ? (CicpMatrixCoefficients)matrixCoefficients : CicpMatrixCoefficients.Unspecified; + this.FullRange = fullRange ?? (this.MatrixCoefficients == CicpMatrixCoefficients.Identity); + } + + /// + /// Initializes a new instance of the class + /// by making a copy from another CICP profile. + /// + /// The other CICP profile, where the clone should be made from. + /// is null.> + private CicpProfile(CicpProfile other) + { + Guard.NotNull(other, nameof(other)); + + this.ColorPrimaries = other.ColorPrimaries; + this.TransferCharacteristics = other.TransferCharacteristics; + this.MatrixCoefficients = other.MatrixCoefficients; + this.FullRange = other.FullRange; + } + + /// + /// Gets or sets the color primaries + /// + public CicpColorPrimaries ColorPrimaries { get; set; } + + /// + /// Gets or sets the transfer characteristics + /// + public CicpTransferCharacteristics TransferCharacteristics { get; set; } + + /// + /// Gets or sets the matrix coefficients + /// + public CicpMatrixCoefficients MatrixCoefficients { get; set; } + + /// + /// Gets or sets a value indicating whether the colors use the full numeric range + /// + public bool FullRange { get; set; } + + /// + public CicpProfile DeepClone() => new(this); +} diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs new file mode 100644 index 0000000000..390c6a263e --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs @@ -0,0 +1,86 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; + +#pragma warning disable CA1707 // Underscores in enum members + +/// +/// Color primaries according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.1 +/// +public enum CicpColorPrimaries : byte +{ + /// + /// Rec. ITU-R BT.709-6 + /// IEC 61966-2-1 sRGB or sYCC + /// IEC 61966-2-4 + /// SMPTE RP 177 (1993) Annex B + /// + ItuRBt709_6 = 1, + + /// + /// Image characteristics are unknown or are determined by the application. + /// + Unspecified = 2, + + /// + /// Rec. ITU-R BT.470-6 System M (historical) + /// + ItuRBt470_6M = 4, + + /// + /// Rec. ITU-R BT.601-7 625 + /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + /// + ItuRBt601_7_625 = 5, + + /// + /// Rec. ITU-R BT.601-7 525 + /// Rec. ITU-R BT.1700-0 NTSC + /// SMPTE ST 170 (2004) + /// (functionally the same as the value 7) + /// + ItuRBt601_7_525 = 6, + + /// + /// SMPTE ST 240 (1999) + /// (functionally the same as the value 6) + /// + SmpteSt240 = 7, + + /// + /// Generic film (colour filters using Illuminant C) + /// + GenericFilm = 8, + + /// + /// Rec. ITU-R BT.2020-2 + /// Rec. ITU-R BT.2100-2 + /// + ItuRBt2020_2 = 9, + + /// + /// SMPTE ST 428-1 (2019) + /// (CIE 1931 XYZ as in ISO 11664-1) + /// + SmpteSt428_1 = 10, + + /// + /// SMPTE RP 431-2 (2011) + /// DCI P3 + /// + SmpteRp431_2 = 11, + + /// + /// SMPTE ST 432-1 (2010) + /// P3 D65 / Display P3 + /// + SmpteEg432_1 = 12, + + /// + /// EBU Tech.3213-E + /// + EbuTech3213E = 22, +} + +#pragma warning restore CA1707 // Underscores in enum members diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs new file mode 100644 index 0000000000..6b421ab9b1 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs @@ -0,0 +1,96 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; + +#pragma warning disable CA1707 // Underscores in enum members + +/// +/// Matrix coefficients according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.3 +/// +public enum CicpMatrixCoefficients : byte +{ + /// + /// The identity matrix. + /// IEC 61966-2-1 sRGB + /// SMPTE ST 428-1 (2019) + /// + Identity = 0, + + /// + /// Rec. ITU-R BT.709-6 + /// IEC 61966-2-4 xvYCC709 + /// SMPTE RP 177 (1993) Annex B + /// + ItuRBt709_6 = 1, + + /// + /// Image characteristics are unknown or are determined by the application. + /// + Unspecified = 2, + + /// + /// FCC Title 47 Code of Federal Regulations 73.682 (a) (20) + /// + Fcc47 = 4, + + /// + /// Rec. ITU-R BT.601-7 625 + /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + /// IEC 61966-2-1 sYCC + /// IEC 61966-2-4 xvYCC601 + /// (functionally the same as the value 6) + /// + ItuRBt601_7_625 = 5, + + /// + /// Rec. ITU-R BT.601-7 525 + /// Rec. ITU-R BT.1700-0 NTSC + /// SMPTE ST 170 (2004) + /// (functionally the same as the value 5) + /// + ItuRBt601_7_525 = 6, + + /// + /// SMPTE ST 240 (1999) + /// + SmpteSt240 = 7, + + /// + /// YCgCo + /// + YCgCo = 8, + + /// + /// Rec. ITU-R BT.2020-2 (non-constant luminance) + /// Rec. ITU-R BT.2100-2 Y′CbCr + /// + ItuRBt2020_2_Ncl = 9, + + /// + /// Rec. ITU-R BT.2020-2 (constant luminance) + /// + ItuRBt2020_2_Cl = 10, + + /// + /// SMPTE ST 2085 (2015) + /// + SmpteSt2085 = 11, + + /// + /// Chromaticity-derived non-constant luminance system + /// + ChromaDerivedNcl = 12, + + /// + /// Chromaticity-derived constant luminance system + /// + ChromaDerivedCl = 13, + + /// + /// Rec. ITU-R BT.2100-2 ICtCp + /// + ICtCp = 14, +} + +#pragma warning restore CA1707 // Underscores in enum members diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs new file mode 100644 index 0000000000..f9bc8d90e5 --- /dev/null +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs @@ -0,0 +1,109 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; + +#pragma warning disable CA1707 // Underscores in enum members + +/// +/// Transfer characteristics according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.2 +/// /// +public enum CicpTransferCharacteristics : byte +{ + /// + /// Rec. ITU-R BT.709-6 + /// (functionally the same as the values 6, 14 and 15) + /// + ItuRBt709_6 = 1, + + /// + /// Image characteristics are unknown or are determined by the application. + /// + Unspecified = 2, + + /// + /// Assumed display gamma 2.2 + /// Rec. ITU-R BT.1700-0 625 PAL and 625 SECAM + /// + Gamma2_2 = 4, + + /// + /// Assumed display gamma 2.8 + /// Rec. ITU-R BT.470-6 System B, G (historical) + /// + Gamma2_8 = 5, + + /// + /// Rec. ITU-R BT.601-7 525 or 625 + /// Rec. ITU-R BT.1700-0 NTSC + /// SMPTE ST 170 (2004) + /// (functionally the same as the values 1, 14 and 15) + /// + ItuRBt601_7 = 6, + + /// + /// SMPTE ST 240 (1999) + /// + SmpteSt240 = 7, + + /// + /// Linear transfer characteristics + /// + Linear = 8, + + /// + /// Logarithmic transfer characteristic (100:1 range) + /// + Log100 = 9, + + /// + /// Logarithmic transfer characteristic (100 * Sqrt( 10 ) : 1 range) + /// + Log100Sqrt = 10, + + /// + /// IEC 61966-2-4 + /// + Iec61966_2_4 = 11, + + /// + /// Rec. ITU-R BT.1361-0 extended colour gamut system (historical) + /// + ItuRBt1361_0 = 12, + + /// + /// IEC 61966-2-1 sRGB or sYCC / Display P3 + /// + Iec61966_2_1 = 13, + + /// + /// Rec. ITU-R BT.2020-2 (10-bit system) + /// (functionally the same as the values 1, 6 and 15) + /// + ItuRBt2020_2_10bit = 14, + + /// + /// Rec. ITU-R BT.2020-2 (12-bit system) + /// (functionally the same as the values 1, 6 and 14) + /// /// + ItuRBt2020_2_12bit = 15, + + /// + /// SMPTE ST 2084 (2014) for 10-, 12-, 14- and 16-bit systems + /// Rec. ITU-R BT.2100-2 perceptual quantization (PQ) system + /// + SmpteSt2084 = 16, + + /// + /// SMPTE ST 428-1 (2019) + /// + SmpteSt428_1 = 17, + + /// + /// ARIB STD-B67 (2015) + /// Rec. ITU-R BT.2100-2 hybrid log-gamma (HLG) system + /// + AribStdB67 = 18, +} + +#pragma warning restore CA1707 // Underscores in enum members diff --git a/src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf b/src/ImageSharp/Metadata/Profiles/CICP/T-REC-H.273-202107-S!!PDF-E.pdf new file mode 100644 index 0000000000000000000000000000000000000000..12086dd77934c4d7b2d2389ecda3020815a8fa30 GIT binary patch literal 2632310 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

|@1sAy1=gLHv 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%0Dn)n`+FwIJ=| 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­|X6(1tiq@K#gB(Zj%`^JKkkVegdMm6P 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%0Dh+UyEwFd!mpb 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

k_%Kxi&1s0r}Vch{OMk+JA<>AW@3E;`QZ24 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 z%0DB+hACS_*78d6fsr`0Vd+=rbwH6SQWEOilbXC8^~Hw=8C=1aspQuxfOmW76vKSY z_BCJ@ZH9~7t&OwQz4i9p3kJQ*g#`}AQp(n5>uT?tmZ~JFF4^*MfzQ&351XXVe$M%F zXtr#4NTUL4@Fhz(Z!K?Nnj%sAl)O zUIc~sf4zxk8PIUUm*Y;A70+9%*uF_NwBOj=a8;&F47J;A?-Y+PZ&1n>vg1Nddn76;QPE&^g#uCy`>Px1PbZcOVlq1B1AeqLC+__^r@BDeHK_@+?zWG zP!+Y@E8F4`nO@6zd|)#Yh2DctoX7btbDK7OJS8L^1|@ls?0>AB2s^G~W8{%(caz~5 z&Pbm7LB{x82lU3M)QDM)r_IanYd+%O)09Lzy39K1xDr66J>Hn*7(bJheb!~o!q&3g z<%SrCF2uD7yw1d@D;vK9H6=!l?qC6>7manUYjgN?Em~LgJngHwO6iKfEoNN8aZ}Oz zHC->a8!d(v5leaEQTe%O1Zw*`Du@zCBf}GV>XGwn`+=C(@`_$-Bl7hS@bJ!!s;%#F zRWd2{X&3sXve<^l{V>lb0TKt+Z$|x66Tx6}f<$z7r{4t)xukeQbNRqruWc@`?HdjM z{vStnc0=0rA3PNsUv2HQ7k8SPy49{G;+~;)WnS6B<3G^5Kyn2zIiDT*Xj|Dl%x-Jh z{@(G4htkAZYeZ&`d;-a*Yl-ir8U6{9CZpK*$jAzxad9iZRmSzX6?xvxCixcv20XYR zg`wpWItOk;cK9!XXkrf!-pPEt|a2>LjhfvGN$mFZ*lUgn~ zUy2#O1gbDR&>!+(*w6E_BQ4!$Rm3QoV}Ls%(5PdWP|%UOudU4+W}?>!d8t~9MaZjk z4A@8D%n*ae-b5pIVul?zeS}9Hm_HJyInqIXd%c4rsv{`(V>NAh3Eq4Lvvw|4p~#ut z)|t!L;lQjx0C*XgePU3^dGKZYv%%5No6UXX1?{1R-GgmAPQ?RiFb=9P7!KO=q5v1F zPeoQ2d8P823Cj)?`ZI7|>Z!n@oxl$oB5kjQ-ug&5IpE*_Z{3T zo)14_ph4Lo9UsZ_ft%vX73)({7SenD8XcJ5HmX}pd#G*CVMov>pibXd+^W?puBt!Y z!6L^sP2QKZ|=;q?m%G{&zQlcu^1Dkvy)EeeTz@u0+ck!Cvqjgym zec*tBYtP&@y=m_6?1nf%DxnY72s3X~1X8|H2y;dCVMIK&)1s>6s2t2sY!Pq^dI$Yy zJi%`D=YqEMiV}`h%3$(YH*O8xyNcoTKxH6o{AF?)J;b7ylbnEhozy%hFuO=k=tM%m zzEIoxm^{NtjxX}Z$4Y{qKh8~5j*8tOVZeh($bb$xny9=X;*awvkh)Dat1{*EyxO znDBgMdXW#elxr$HyyqDo^GZ_%y!@kriE3LU%k#6K;f%VC$uPu|3*x2qQLF8Q(u9{K z&=nafSXRwCHm5_ShyT#Z_{YU8dC6Fl0#oX^lKBHm3+a6B`nuZ-BK|kVN#S(w-u!I> zkTW77B3P!twzos#jsfEII*Txl}wy@{-zhH z-5u~IgGno{vN#Xw90)6ZC8AC?APwrUsKvn0*PT1F69VES?hM99e*vBDivtAh_2$3l z>}l(tDXEI^5-H>d$kyYe{2YCCU>{e!kmHQ5JoIrK2oNl)Wq$68et&h`LLgG2qyit? zWDarQlw?17I=GPZk?BYz2Jn6QG;;dWs8DX-Spk*u`~qnBhpud8#oA%S9ZQc|u|6b< zBzPm-?aJ$>%39!X4=Ad@-j4}po`|28kYbGq#)OlX5dyIw+|FPCFC?;?G$7=)zQLSl zMRA19<~*`Is!LoJETQkhqo>PlayOEp#d#enjiwtjJjNstH^>FPymhTsqJr0tMV<18E5o>&`S}{#t|0J)>w5!PYUY2oSp158|<(F+1(!%0DRBb?a$neb0Y2^Oj$KH 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:iJ0 zpG2BC2ZIGCdF!#brdjgag0k77GQXeUJ>BuYaJA_W#GtTau3bUP3kYf-oCgV{n_KwQ zi|Vy0_ecIgS3YiHk#0HCoZot$W9|D$|3(G}A;NzG#6%8Ox%_YUgZ+O4aw1lc1)2KF z$}$0h#h_8JgIm}I69p-+f@d?JN~nB$*`k$)e&&&GZm0IJ6^>@!HsRTeYbbRBqLq2 z-T3b5`}#4#bpH)Tv5c{u9GRrk1`LiyC1$AE!gY4d7X28yotE>@E2S%F^|e>W^Zdk83EynZ%~8qg#EGZoZ$t!eY%x)}~fQVYRIZ6NWg&A(QzY{;zuD|j?mq6-K0aB09|10(I@uJ6p z)*UYo7T~MC=w4$rZQ0)F|J>{hsJzd0$Axy=Y5K3NSCRsIWSr2INuUp_v0%{Dh1Yuh zfs_b?f!AC0<^iL8M&hWxGJjJqq5%JLV#bm83Gv~dw%=7Rz&BuH3%Ox81C&vzl=A9w z;#m~fOEj;lS!Pzo|Gqw3M%Vx9_jXX=6TtE8zU;lNLHJQ1Emtl-55zgyQ;K*L>|kTf zfd`uWElBNHwy>UYlq9keO4vZIoCRg3iSF-mmS9Cj8C5%4nA%v{c@T>6oi*-<#2XJI zurKkhiof}~dEUkismx54;o@S)1i%dH_Xs3tsNR1zk+X&X<8*uE`$}V!n7Zo-H~at> zXCW?8dvppr^Nj{pA;^^%4=Z)OY4#*t*v##3{$x4dEvjIb%>t}guW-juGbd{e@dN^P zUl)MsJ{dVHpZSVjFZIq%dU$xW+*d8^3)W@lTZvG_i@$Es4HYF$b6-;B&T79FWt9D0 zuOPC#ka^MvvT~vgjG+Znm!#^usVf!HEGjgos2(;B`>h6{gALv65U_Fczc~ehhp-oB z+9rds2^C0nOh@SAOt75061e73hwIyIQ347)Sf8SwphNRF43KAFmeX=|WukmRb8@6B zL!`~k#&cf7NL)tQ{_}D~HNR&pfQSzGP%c3Jsgs{4*{i1iYCVNKOsF7QulQAIC@SY_ zchG6G7nG~D30lf}7QC}YI*?#%C^Eh6=&Ut`<*@r$a?oU(V4gg`Sis@*kLmmr%S{BL z$3T%U0q|a?L+Xs?c)E)9ASa&vZSaBMo!RUu9=!HHXM`O22Ah08~Z3=OhOh z;^v-7!>K|-(tU#hY!0Dq-Gyll!9VK`H2zcX^5pmZ6b3<%*6 zz81Q&vYdLyf23)cjP#&~qc<>$1ODg3+kPWPREpF2yKe{Gw%XbPzNmkJp!o%>S#I(U3EPY+mEHDkuT37VbLf zC0Q(^=I^xk)7pMNFRQ4gjXAbpPSy;fLhZRU%)-X*H1qw}_P{oXHa?Sh#<%FSt$^Kk z|HR6}lB6{;T=SU)x#DuY0etJl&vqd~zGc6XtQ$}S#i)o0&fzj#K_O5!jUoAjV6-BY zM)Y%(oAtKNEL_ptpsATCD;pRnNZt)8Qi9~_e~<&8nKW1itXaRmILXr$o0Op3!40$wt{_$&j@?u z!s%t>A|8{-X;QFRLGpuhh)L2!S7}}ad(Z9vn++fQ{m=Ifv-$jaUq(@h zV*KQCsr%92)+?{5|J==sc(TI@-3&rjImck|Nw%}Y^^)K1k>2Z>z`?eB_PT-;2IwUt zEgWSbEi{^J^Z9Quf#m#_TzbCYT(7E{hjMOf<|-&KB`sCIsHlX^mx)~J*QZl9F;5v9 zsb&-4@SHCDf5e@ssvDI~GJS3Gc}TGG=hMs*{e+-LO2ypY5;PHL0DBiCPZ|}=adN+k zJ56iy3M>PnKnV#|`0g5&;)TF=drI|VFEDaSG%Dan#<=xDE4_fbyM@Il?s&hUFBdno zPIGdTzZ1^~G%L3L8I|&1V%ozY<1n6QTS-TgwuS@-oEIZ5hjb|^DP04wSgN|-Nn)XK zO6taWA$rE;AG!sCX%I8^9Q|i%3#Bn{!)+g<*Apm3cJ;xs{vI4=KAObVuZnP2)zH2B zrGHG?p7CL3Zf~-T_Axj3+%nM*HQww#-J%h*IPK|`M0H0I_vW2(!ZbkvyG66rS%~dE z0s{5Z3dLAP3Am+l=77Z(_q&fXA7P8{9 zeM++GP?EEwDui zUuIZPZY=wV|MYBHRp!rC(r?YuAz)3U5AgW8l2y0^Z3m3>@1av^c;VOhBsxN8y}!QP zb&*Ha4H(+O`n!qtORCSp#;KMQMvs*%_}@k~-@0D=Ary7*nweEI(D4O-FgU#x!g7f5 z_w=AskHn7w$P7Th$-s+e1VpMz%p*g6ma5Qa_SeCbRDO1yOQrLu(Pupy87lq za<6~Hi8@}{ArnP zJrU4&CWMvxl;x^bOLyPx(xD)T9yFKCNqR;4OM~aL)*Fs0)x8{yJSXaSUKpCJKbgnYfIXL9lsIg}Xth=BI;=2ov5|r(NG>q@^zW;boeFlTwZlmOi?5cRne1 zq~&QI(5$6DpNI)vbO{DYTd9`)aRel^nL>sLBOJfMLY+{(+Yu#6qORS|JMi4!VtHW)lsmdm?gs>3fgh=Bd zSdbl~o+v#po_JVlzV}#KM?A9s==$bH^*<-CJh@LniD=RARLczYILl;UBK_{iZiN#D zgp!cr7#}tHwr1O*X&KA-ro1>`PRT9192t3z2#MdNLseq#fB2PT`YR6V~#bIX|c|N_fnzM4WkvY(9DvtQUtX6e#P; zd%ik14iJn$EPQdip_6(wbP_qqit`O7R*4MF6(ejt~-GsA%>5z-Sj&q z=ElF%dA6EQWe)t$rV3XGg7{0b)K%h#o`91V>P~$+ov|;5KgT2R!TS$SxRtjFS7vdV zz8e^X-0>00aDpLT9Uf^jNQT;78spyQ#Xgi`6!FJyDJ#hn9gY?>`Ot*kdM*J0cVW++ zcg^!Dv@9Bwq9*Z<_*~lh3%^OR5ZK^cv(;r7!D6e!6}6WZFU@03-iLgV{#fW-WCi( z&JO6N3*9CZL`LKm8@>Btl|+RDeXea>S<3y|9_u|`#WcecQA0g>$DX%QRNKL%IM8rI zGPMCbyqM(-_M~LrK;fBa7fYIao`g{nyo2GE@GFc^w;@Ji?gR9H-{UX7_cu;+5P*IL zLx+uT)t>Ypa(=AximM-nyw-f`s?5ID4%8Y5r@KzFZ2mQn`i07R_zB;Y4FNgoaQEj$#}Jb8`) zPjxn@(ME$mp~_U+a|X`^Hne}@=MZo5vYlZ98iOwi4XBy@(-}ScY|`MyWG0^bIE_B1 zmL~?dhhQX{%9{mNXdM4!14j6Dq8oGUjCMJ#6i4cO^A@ zsWx7|t;;j;p}U#P0;jnwF%XuXn(UrVlV5r_mwu`I@p#}-GBzhMyh`XA?ed$&(FxtW zc&Z~mt|GAmwb2Aw3JWs0VFM?yDX4Z{sdtO>)=EC-ea;zHD;)3W z=sF_tzs)`uY%E?)(^1rE5#e@=-IZ_#SQwX`DtQ+6Fg4s#!a@B&bDo48N2%hmwJ$2e ze^hdKd5-?&+l_0vCk$UvYHaiw?N=XhLyK)mUr$fPi@sT$M}2ADr&G=_(8pkbP>4hL zNP{N={Mb)Kl)a`>h`v%wA28?~uy!KjxDB|dG)`%`+02YYyy&xav{lKH;yTAaeIlys zr8~lDY+V+qY7L3k{p1o|jSRm0WBL`)RZ7bZez<+VD!^HM1$(}csnw>6w6suL?;Ff; zlv>~K8ZB;FJPCvzXDhRL;vCR_82Z1<@f91B7T(ahCAPuLi6rj$7gt5&gd$8AWiC?u z%r*(^5mcNSsfvC*B<_ck9WzcY(DN^29U@Bxn-o@isYF>nurSgLLcEgAIxjot?U07w}M|M*nIH^#1+PYINn2KZZ}KG`?2-gz5*PFYoHnDLI^(jHQ5AUj%y zQqxlnx|?QFIF+`JVU9IPp0p0>7p!>%e%My`%yD=}|=A_?TQ@)CC&Mmh`Jr zT6>w$P+duZl)@%5n4<)vw^y?Nnq0O*nQlOx>;Iu*0Op8lACCOXdiAF74Sv;Buu;b} zw<+au5r`k@+~kbTXDHp@HYXMPyBP-lHlY5;eDARU|iHJme@VZo?|L5Lm_9r=HdEnpQoUd5R4G<6Z z|6rbcs`F1Bl7|qFmRG7@D$n5_(zw^G5>>=^PWR0pX;b6z+>$A6O8}X3{xAVIh zg@(Jzw6s41Ckzb%(Zog&Pb*WK**^04QAE#JOWn#Wr{eX72EZJjp^{pP4SWs*hqy3I z9Oy&;4eO<%LeCGTAFT1F(h6vMI1y?3U-!Pi%plMpQpF84r^ckjIr;&R{~(iWS&@vt z7CFoyWkeE~2pjQ)$HVU-0I(W(?pdGl5yM?>?Gg}mBH>t<)yKiunHmom>_q1W-1!T%kH-H# zyxHxj+lFC+kgFnI+4xVkZ=yAW$3*V#51sc(CNYa@-ng2Ht*HnL3e6k}(0G zx{XQJrVFnOf9FtG)MgeI679=VmxMn0iQ!6A3tGNALtVAzzde~SOiM^+EFvp>SJVm; zFV}6>jg0(h@O~kRdLMTHQUEWjrmq7{Vtq03mCjl_g7Yc*f=qsX41AWGY->O<75}(? zOc&+0q;PtB15st}7qFiMXQo~ItLI0by5&T{t$iPfXUcK`U;21J8;tQcLc;!`Zwx%! zW+DA=W`;GlDTu*D8^zjMT0Ism*S%3T3r~3;j*bcm`xT^ZzA%G;Oe10Z16Z6@m zIW1&8qLplfvWc{G@_6>#Q_1wPxYBm+LU+^igMj2JE6Q#dNW5@DDETx}don6gcwXy1 z**6>-QRsWkttCYDIW3^jsfBpLs~kWZznjfwB2TM!4X~CXw~&pMtoY}&nFIT4gLcn0 ztqCy|prcb~bC`-}a+%um=SLRK8#u!;U+wG+4FthK2N2ja49aT!aDopX2D^rkI?u4s z@UfH@G48@m{2qh35^mIy&FY{Og$jjh6Z@f$ge}6egA9=@NVKLk%WG5h_o}@A?Db}j zx?5h>y#AQ7FT3U;DD4PG(Qt|Eb#psO?C>6{#j*7sI&Zw%5H+Jj7`2G(6#(uMt!IFP zN3dC8SFLiv*G6>Yp%_TfeuH~}XGo#-ZQ8MMJ-k|6Rm4onXn2@cQPFDHok$*nNL+X$ zM9PhhIyYK=t;P~S({vk#O!-hs%?j7&4+RMpr01+PYYd5UW$_^6`?qiw0*c+`heph! zKxS9K?1gWRDfvKlv2pr?i!0=$(0Lt(DFT%3a=Lp8*ikX>wz1q3`wenu^4%Q9G`^LE zj^r@9|H*>8@3UYz;4!hDhgMWbSOy`Bv!58$)2Bt59Y^%(&w=FUgA~4uv2dE8D~;85 z`p=HW*a#aN8yXRh=y4S(ki!0zEEq^v)9m=6kUs4mpzBV*pEmw zvoYTXFX8Ot2Cv(TOXfa(>YqU1jq@g0mP0~34VsgR;hJ8*BBMOA&CHro8CEO+)Lw|6 zbAA*R6$v(1oD@zg3>FuMceY_ZuQ$Sh5`NForR?!&AGPMplC7ILO>3B=s4>M(p$fT= z2(H=WzwK@9M^gsNowk`@3EwcQTKvNcY=g;;8&4LO7FIIOJEpdcgqXmq!A=*MuKq2c z`lhSjchk~xDD*)<*4)~?Z8w?g@`{`*_%30tuNXA|Lqpw9QRr+_X{*jK(2~b?+d0t| zI9yNlD@q;5```E;!sH02C$>l^nsQi#j?9PKYke_z7k(3s0D#Y)ql^wI%QA4XL!I%= zVmcn#9mqqp{KD@O9==h})!BQ`JJBlDk038*%rvA(1NYv| z$N#n`{}b)fpxIT`{(bTHb&|$sI?f+e-z@f;>3~za_ba#mi?+86tE%hTKot-P2?0q- zNs-)icXvulOLq&1l!(#-n{K3~yQRB3q#LB0Gq=z4zVCOg^ZWecT6?d(7ITg{<{0;V zk1>7GE>5~B9F2ARvo6-Vx?TP(KVo1oErI5wq`EkZ8}Cf)V%HFY0Nszebj2+Ai+k&d z1!TiXeB1lVa3Dy`RJqSsM}Mw!HewW%yui_5$vwxyZ9OBw#AzLw(UTs}Dp}t7xYdsU zSF{lEgEHr-?ryceVuQPfI{retp2I)j!Elk4rG+q=-I8>S1S`W0*A-gEmI#_vBj7BO z%E%3?qb}8FzRqJ6(=s&LIiI1mFz`{t?y{sou#qZW@yCr5?IK{UI4RxI?QRp{B;~IN z5wMxT<*F?mkWc%b-%{x^V}2158cTX2TU&Jn&Ib7>_LmOnm80zW4h{UiK--m>{r#d@ z&Lgmy)1`UQX*oVDB_(j;bMm$%Erb&%82V9te&;BW8BL{T`f@z+f4KjGOrPeb}l`rSIplGqErhx#2?x2s$mCOfcz+9~I>W%F3!-&W>I;DS18oE?M*c*etq(evy}1@U+LICp$3)1C|J8UjkC( zSUiPa5T_Gtc}>F!EINYkTi~gOlvGtwwd%_DSvGZfQ6S{5SwFt^+lMOlykm?UKUq1v zlavA7J`CSH^G28w-|7!|YpV>+{*LzS;ez-LVa2o0KV=qTU7g$*Xu{|NPR;^cum z|DyRJ0pg2%DbzQlyN?1#%&%u^V{C3@>H2f|O*VTDGq#aAJyDO9SmZ8Nng^+~8uL-p z)`xF-&?jpc(D@qwLAjO$ucg0u84DvxVXcg})x+sbE7*L6TV-_+>}rZd&8bBkatTOE z0qkTPknHVYGnba&=UMN3ml9ph%ZJ=!!HvPKjQ9u)A2664j_ z93WY!s;r*OW4!1e-0Y}_@ZWU=j!eNZ|7!l4h}@!-fMs;fZZzZPXLYMp+<<##*M`(H zr23yPM(|3Oj2VL-D#5`Zeo0yBcTd*%28&md^twb8nv4c=vgs$U72;9UA3yMExrXj$ zV;FsDm-}3KdLI?3y0=ZtJnC~=0X>P6EHtQfRbAeD*KL-Zw4icM($rqYe@MQ`<2>)gNbo9xIeM?+Mt55(Z zcPJRokCrJ`++Q-m$?A~a`H&q}1m}i>8jSh##(__%beP{k7uBX)q|BQUMq|+4Ciebk zRh_a>F(QL{$H4jUx-ur!yW_8@Q`)r3S%%d1Jg0;Qs|}SE6~1p9)2qa#?iumj4czY$ zlM2$)2?)xcXfw-@>6^iAE^dDys1y*^k#tMa6!MXNGK2f{3;egu*>BRg8XP36-in%R z!-+<)ku5TtT;X&ee75NSshv^dq4~OYgfie0XfXiPeYxo<#e5rGnLJ#~hft z+ydOhJY+R~4bd-jRX+xdvS1@QR~-+!FNGZ8x16}{D=^jCw6+9~mho);`hEEO`L11c za~jUm|C)eBe8{g^k_U&13di=z@$UFb`49`5K|S+@$^Z+L4mrxni=EZ=gvtH-GR-c^ z!cbYiuhrQXXjI~n@fj@GArp&U4ZOS4vuJagC9+Zj-Ss}Xn!VUBzCb_d4T0^)c-2ip z%x(ts{jJTfS4sH{fJc=N((Q5qE04`g^)61eTA3rpC&ozkR}PlfG71WEvx^|+tx>>R zocJgLoSfyoev~U|83BumsOVVRXlI8_Qf=V(pd9L?`U|D!cW#fa3 zkWkgD{q(>oPPR{@SBgpc4xv>!C@f$mSdRXn#^>bafv|aRk7sgl5!utw7`yy(?JGxE zWlZ|(Dpt#N<@r_uW5mph$IjibGP7;;)L1RpdjjkDH~Hgy>qMR zASfn~i^o;mkWs!<(tNci!Cn829W*N(A3r}%cK)r6dMHovpWxzDzF*8tRnCl}obC-I zat0?F+HDOB0z2Yj`o)ao7X*{*bW@#f;VO=f1RI`-8L6;h8|e)#s?S?9(bhU{O<#e~ zuY}|DC*z9_wrwbK>0qw!_XT(RtQx+}>8m!UDZ2$<5oqI4rSyRypugGBHF{)dz53Ut~ zYe)be`Uk|uV#OwS1`V+ef?bdf=ojMV6R^WU7xgiSa?{i>J_`4zE$Z&ugTK{uHjMzW_2J8uc zu?nR!WFB2p(-)$~*iNYQS5R=!MSlM4Ur|;#%-*7+pEGjpXs2k+Hevzsj@jMPB30}M zniIryM7cFu>~4uTIG>%a5q6CCi-?M<+2!QmIu>&}eaN6j zP&=CZD2xhs?{GE{048b^PYoR5xQ&7#9>|W+~C63;$g=A9UGz z$ucUuc!pa=p{=FmaaM;=E5Yqjy9kP#`(MXdrL{S6lJ)+|D__&IbHZc%&p%LZEBmFP zIX3_i&)`R-Rm{NLg>WwO;GDr?hgRJOhVi-kSI7I6t>fe460_j~p7|=p%2;ludHMPB z$t;?S9e<8al{Kfj8M)}EXu)a$C-fxfXvf7)^so>AZj*ieI{!ZtfzWm)XTq#IB*xKx z1{QyeSWOBr^Ic$`H7Wlf-T%LvFEr#?(BBmW?445N@4A95kiUik=JHFAoHl}8*~yT# zl$2hxsigLK$gUfyj7NqM5Jn|4L7ZgM-;^TfZ3lm`UG#cmO4b3+hV#QPWyh#G6u`%h zYoMazFR9V(T~lI#N&{?l$iPNs{ySPnh++?y=e1?QksBR6Y$2OWg2jKSFWUUmVYfKG zh8U2a>y<^`CHIjVzkqKTZb+@uWwKpTS;4x%jnR)R6TZ}d(F-LRsO$i}2#z(^*?EkF zlAg`|M+Yh`Uv9tD+IIGb*LYPGV=c95j)8&qn%WEwZM(yYf%lw5zZ#U}!X}2p<>7Qy z@nOJgrJ6N*BPBIGe--PZ?FJE){g$B@o(lfQU%7C08elzQRr zP^QE{TG3!U+-5=6Z zA+S-C-84?!$aen5GUrqznp0MS4{f9Pg!jNaIW{#p=%YNn(^pv(!J%551|I(fp6)IM zzAGtd!A6oBQ4U47;tiI91L>v>?_NE<(hmQ5 zf*cRGG`37d?|n1?-BUw`)8vy_QNKVqDWA=9zA_%0al%W@d%q@*20B>=mpnWUzKnU+ z#bT>4Xgg*;5G+)_$>i#A0o2(^{DP;}6Uix?6+XhCj9}v7V0wF}$Iq$IdavP@I`EC& zlMP~X%&?cvk&PvCI0>vF$Ar?N14iUEH6uZkjnr`{)40&J%$Kp7 zV`CTpcOGJee(4TMN27@h72Gsn#%=lCc_6f6>gq1gcp9l1$*J<{z|CUO*XRU}E5&b6 z%#~=(R3?T+ZK+wQo9dLwYO|}ld~srQ9qb*0`afLU!+FBC;F$iXAShdfU}`n3?$Yr4 zKV=i9oFqbXvV@~4c)ptRJ8!F4C3Gb5I!8d-9`l$QNCY(K`E#dTV_toA1rK`Bx0LN5y0;6XW*pV%NVkb41&JoS6^Q_ z0FXknvBAMq#pZqcLoYp}o4q4AEo%Cw3tsjjh~U2^Gl{lo5a1Jt7Wn*`Z7jZbql^IA zd;Z))K?Y|#+NENGPkMre9Wa-mFh8oksjY1ygy7;gB{sXnmqPc8z+b4YpB?=c>1wpx zH`_X^ff;HK!)vFP`%#OW93o`T~{|3&BMkYI-G zpr>0_R(34qm0M6<54BJPlsSmHf7|kRUX51@tk%Ks2dRoSjbB0zNeg_tIycacZJ%>S zT6g4m%a$ym-ta7tKam+bJ3IOj=>xY=wj@mT$#?Pa2DnrDn(o*&=VF+dSoq%NF3?II zX;o4mkn1>*g#L#P7N33m)9}Y>hy6l?>A{iwsTx#&QQe#Ae^z<_*E31P>x@LnE zAALpIYsh`@aJptYV@H`l9bD&NoPHB_tGV)96Ab?^LS$Q!#1i!)9QlPQ4qeA znBkpZ6a4#jektDPw;lGxOCR%w*I5M9CMBD_Zsdbj`jd#-*z;6?32j|^sH>}cd$;G$ z@fU`-P7>ez=6Lg_h|cc#zu|NiS^wI5i|q7BY_sWC^|43O}EQ#g>CY2Wkj!Bnzw*!os6C+JeTPY^t#JNh*I{Yyh; z_RsP5I8UxYc`$!rR$-ytJ7>U+6|1O%bDK7;*NFl5S%bvpA2Z3dY9EpV3Vjl^M^i)_ znFN^u-;V$nC|Rtjp*%7%(d@oYq8Ssr$O%h~ESZ)-v?$L#-PZ$zvm~YA*l2(UQEQ-n6y5U4UFh&=`t9X{^sh? zJa?Bc@xNpgZ~+lvB1VXAa2`mMEit>+viy&1!Mw~oG1npnkgAZwUWY0x8B+!(;?L>J z#x@PI|)#20>Hx5~V|xVA$Cd3;0>)x6_e62rBZX zO>U94i@qy+Jh;WH*vw}NG&hRV|Cu6>ju*^rF9vLG4AJlm$*R0BgdOSLD{EOG0$E=* zzuU>tCnrfBE_T;vN*QVsZrHv10)vTX-*EwE>~(tcl^a#uNlM~tVc~8T0uSKKD>}2d z3gxMip=(JsNP3i9*3vS$Vivd!BNJ12@*@rohwJ#Ys_{K{!Oe(+=(ui9v6}^nbbdQJ zH_{Kb=7+y}DS(Oy$O(l105D_=_2*uXfC7m>KpG3fA16bT8r~KZr$5du`IfaE*ksyx7+j-K2u4YLTFqYSNqpe9BraMKP**+kMlZ!uuZpoIN*U!nklny6?s zbF*QJYZso>d+{=)#OJPXRnSsEC7he#MXkI+2~9J2>Zq)eRJ!V|kOL=bsj@UvX_A|XZ_!KV?se(z{M%Xwr`*= zUvxC@0t2zZ#*+aaPTbxS%{3gn_OALsaAaiUg<=4a>d^THH6Fw-h<4Q;`PuaE`9N9C z(F=M%LoT-QwOI7jciTo_VDgJY5suGO`*{{bjHU>^Y^=pi-Olh0mS%?l8I9cPV#VNpLZl9|+DN#I)cj9r(-T z?%G^>!mSREqt%jO=@0{pQoypaf)BIYmf@kYd4(B{#m9{NO5@i>Yq3?O@^U~{6m*V9 zNSI)xwk~X7eCv91qI{lF7Ve1OuKg1Ho3Qi*4H}dT6%u(tM$)e0V}CpQva80ACM(B$ z2C<=iP%e$jSeIYQp)9;iF(~qF!I6RMd4@WBe}7T0U74JKCKzuDcVkOiVXP70;7)h< zfMDSES5LwtdN@d)?H-jNF7G#o`i|=Dlh`cpwM^Y6&sPQTe|G@ogu4^X#BOD<#uxVs z5}pXwySslX4@>b8rbC@tH=<@%K}W-D?93=Ed}iRf=t}2lj8#j|)GQ5Cqm=pdDL5YF zS0-*NC)D|ZftF)-vCtxhF(-`rRwJBjSgWr#Q}FoCVxc-BwmoBBaJ#>rp+IK9Ud+wO z<^04O7jrtyTk>;xXqWqjG75yQz#}aqL&o#NV*>|3^Ro}io@z(u#7_D(jKP>nFvvV# zU0-C2PF8UyynWO$g*b#y2MeZ7py`n4fEYPPMn3mb+Nc8+9Z8x8lP4$eK;iHYByBMb z?eQn|WrtK#Y9Y{b;+sUn`*$loc$J0y)t6Xo--v7R6%nc}2+gfLEd=5xfyWv1ZzUx! z>;L$2;-$;16iPT2eR zmN}a^Cx|@mr+l^a?Ck9C8=n$qL$E&y3+0WQW(Tg6KJ=%F|Kesy%ytBPwy$kSP|cGR zW)JEqB2KJ=h6VWykk$VzehidR*g1ogo5gcUZ8~;=o3@zd_^Z_@zClXVpsyEM1#D(h@`BuI>Ld?&revbb#9a!*3 z=~Q3x*}9WQiVoLH3@AVmF{e`gZoAfhnPm2OyOmG}P(%S39ssl3; zVplWAGg(~Fb0^rpaCc_T0Xsak8r%)Iw5W~bt2!WxjECw(Vz+)H$-Y>B+SB)j2ulT~ zwC0bKnD^5#C)fT>8}nCIFy{@~m%r+ZWg-$KeAV zSlK3SArdE>EoMx(3@-Y*?ICcv5BM-T+9JwAa1yQx}8yZYJ+NTdV`;n zSl<=^2oB@~+hG1P%HfidE({?1-pB$!hj{5|>9)6aSi)b!L8PzCbk{)s=Mk#ve19^O z>3NMc1LYA z)+sY@(I!Ks>S}eX=mHIh*uq2Oyi?v`meWCD{IpKgC^7^}ug&s37%GH81=?etEx^`k zDUO{Ayo^HM?;_5vb*i&YIS#M{s2QP2>-(HgP8qj=ynBA= z8h8F@gnwf77Jd3K>4yKp-F17XNpFH*y;?v|*giiJCth0LaGS=ARn7V5#UBV~`r8V% zXZ;aypalA4n8pn2)iv>X%O6zA((Lcw-oe4Px6Taa=-N<$bKJX6ZDPKM40?9hTCsyd zK`|}{zvQg+vD~CIwz@>b*t)QY#x?Du{pW^DgPaJ`xxlj;EMRT`}&xq#$~%geYwXu z_&tz)@yUS(hRZ=&Gn~MD1&?bl>`S9Jx7EI9pXui9KuWtAV7D6V`mLDQc6S~c5KHdc zzf~nPQ@;2Y8#PciNQScUd$d1^=Cl->Ttfh*Pe$baRqwk0OhBdE+Xa^wrCeVVri_$~ zU2b8NnI$**r7vqL&@o5Lez#d`r{Zh94sISRiT1kmVr?U!u(?+T9~qn5Mj;QZKY?8B^AC5&gZaP$vA+Gat8k|TXPmmChLJ4bExd=GtLV+4 z+2fpzPTtwhi{U2sn9x~OAL$SPHkX$TVlMF#&GqDs9p-ewmQ(%0?I#mS#;K;<+oCQY z96=@}ksQ>kqxL^|Lb8;bCsFoo&MERAxa{o3*#s0BAK6X#w8%PSh8r~7y1tlt2;-#I zpaXs05nEsPDExMt+MdeWy`2C_l1f|it=6K91v56%Eg~0Ja`1Q)`xj&j5NCZ-(Itr1~ZExLOT& zYgezMi0#rxn1JxQj&4)6mTIJtP2k!;Kq5$@Gx$ph68FFRz8a}CO8;7S-Y(^r_>_it zpXA;g+o)077NOSg_bTtG=L5pPIV&S2P6r!Z9f}RNpAg!CU1E3dak&;f!d7)^y>&!X z3~&}&R?({MxUX3aDG3n-F0@NgowXfq5!E(qh1;&(*WQ*%h zD_df{SM`q5fM{=nt_D94R4eM2os;;Z^CqF*jpcMvzz<3M3ZtraKGvmr03KGC){cta z%>5c+RI+B_hxc0Bf!8h(=4&p+0MIE9%hlC|hEq#}o_S%zDY1NcbsVFWu{Nq#uBqNR z_>JEBI+5DMY0|;_$p)MiTGjWzRe=RQUE}Kho>VVs9l013+#JnPaI`URi@W?ACa7NV zmb>Lz`LVoaT9-LtK{_&X&L4OSysgU2sjg&egIxsEwaMDfq$Y{JPruIoffjkicZ`3j zifcJAY#2V5q^!0x{qs@B49HOf?=;<``_^Z!+Em-JVFekDcmBUQfa_8EL?OlDr?-XC zmZJNj4@1Te+Tu;ZJmuzcR+Y{@h!? zFBpY5(mtm7^H33JRe;Gwj3S|Y%L-58ZW&DaH1%$x^9{_};WXYle(NvzM#LMUVmqLC z4;oZb4!mR=zC{2TdTaZZgX**+gn`c`dF98Y2z!8B1S^$G!8_J}6M{1+u(%e57>&1D z5D4`s>qXud3P$xRa4@|{f--Wn+Q2wi+>iSNwJnV-i!(D58xOPc_mUW_hIfa=#H3ZD z)xX(*FDRE;O(-PYqs`~n=aN3Lv>6m2GdCVAsz-N2Nq+&XovQv?crQLgyWi2*FosvF zmb{#F?rd7mUPc}E9$b)wT{GDO^!Ec0Y=W zqQ85|Vb%i70H-@^yZ=Z$P~_s>2$i}%AxRU-+74n*#wu2#`mM@BnXZ-k9M7=mT{AFgx!D?py zfcQV@gIcOIMLz;XfD1u=de=VJd*%SP+s_q$ev@WmQI{{cF71jKUzfG%(zn zq3er0EZf)W3fK%%v>w9Au$YNhJDor7X2lP{gew8*dI5)-u&Zv+v&OOfyy&299Br_lV>T!35))v$i8_TW~R4x+$rJV`au!6YG zq2X_BW5;`4%I)77blX(BH1m4hElwkkk=2Efe0Q%cOO7Jm1~sU>HYL<@$*8}5L`J_J zGA`_2Rz#Y%X9}L2X)H)z<$Ym=EyB^N&ADkFq24o{b2av6GEINqzTNuK@^h`3+4^Va-HV!He=-0w zFa~jb`P0pwjfG{dto&m=)em1rjf%mP=9k(%Kc)jh*Nbo@Gk{El-?xC9m4}2d?~m$6 zOe}j;Bvh`Xd6nizF@M8tnrdnlzv6^Fo>2xU({%|cFQ^X_ahpl_N|fqN_Hoc>a?$u4 zUBMOpC8sU+^m!me8T{W@!kvVkD$gll|RBW+xVX;)biBU9LrWV=*(#U-z55 z+!*9y!S?F1sdcr+vEKMTN)2B0)o0fr!s+Lf5L(^zxht8QY#F1|_u*8*67G@<=HjCaz zG1YcIp@G@CiY-3^q)RhtT6{tEDQJg#An2p-Y)lLr)vgp_J2#1AEGr@}noaUyV`7Ny z&d<;IThp_%y!{4s2iJO3-p0f(@yM%N9nE;XI@Ci+c7_)Fdpn2&x*t|>n$wu;AH(zW zd6%DrS{^>gNmgd`uc><9SZN%TlH2M}R-O9@w@c6{gnW^8CSV=!?{_@zf3j)I9y-~+ z1GLE-OFz6%ZF)WHABUlb4YvMPREaP*6w$@l|Jc~`j8k4R~kIB6-QgIjFO2$Aj{iiIJN>62mQq z;XHM#42bt=m_xpTp!MF_)lHMs_E}X$O zj5EL2rCYkDiC@HNJmVAk1Ij(u?Vivul}InuzD%f1ewxmtNP5-^1)t!nRpHrI3XzMt zPG*_n;pka@xRn^-RSSmNPadC^L~p+4wC#hJ1a3>1VDuvJH)wp;rX_w?o^(f}Svc3^ zcy~_h(bZ>3lIM{DevH1lU?N$oRuX(v<>+mu|C``F-Z-~1xQBo*ter|zm2+LF)@IRR z`9wI}DC}PpXF@WH8Zt7S)g#BoVZn<1O+KN2tr;fJkLkQtG0Q0Rehxluih;hj2HEL7 z(G3Oc8XfG~XV|q~xqH;V`xAgOcV3Z0Mp`1E@Bb0WfDK<7A4jU+yLj!spv%h*B2a&&D9O?h}Jp)JOy5-oI|M^WEln&&-UlfD< zS8xLn_P4S$i>%@&t$S!RhkAw2PNRXYx7+GW??N?lgu}o-y{pay;#W16tz+`p4lZC#T2(Po3A)v`Tnp_3Tj^5Q4vL?K_5s zkOl)kJ}S3X9eun1W$`|lkdQ!UZuXG>L!D;hhr}{{$#nc3;^Da&=_D@HUIu9zAW^KnC)pKpQ z>kor5)ku*Db+_IS3CUR)&3Ylm9ZrQ?%zI6szV-EnKN@Xr_9^jXVdbD&a%<6J;$<}? z374CkThA#dcsesOvAZ-kGcsw`i-z)3lNbmJKH?#Td)3e5pyxKSS{=37wN zgn~M$8+V?t!iBBP&U&lvpSl*@<;|}x=V~@aXy`~vj?B$$)5Ki}*S4NPIqD4rGxdFz zKww*X_P6jm-|m+yLuGPOu)F)!MG7~Dt0pbZa)D;!M>Kpcq=sp3uCshRH$_r!>i%fI zdVLqR=>;9eV0_)&>b`-|Uc}yk+0G`-#+q6$Q9k6b`Jn4_$6AlF(ozSzxWv3bDv6?h zUX|#^uknsIkg-rC9d$ya#Iv-L6lrFJlX-7{4;)0}mnl4G+qnPv@pheOv8|}rL}(-Y zm?bEHICFJ%KD&mjZ_L)Ob98seGfs_6DnE0$I8c`yEIydN{;OA+-~@UaHkh6U@>frT zL-X&SY!Ka{zhW}*4!|D$fPMdCj|#vRf#JgJ`yV}50j-5$!-vXx$HmJ1K z)Kb?_Y{_f{yIoI$X`T*xO2a6?Rw@-@C?T~E$L%v^*JwHyjBl%KLDJ599Hz;}r#co1 zZq(Z>>A$I>uxTx;+}65*Il*n12%5_K|NDwA@zOdM_0f3wE7;Up+H>e<=pf?fGo7pk zyI!5wHBWsVgI41<*nOO*=`gHM(-#0JLxye6DUm+7E86d0^um zDn{$c{^pIBkL3$q36BNdGk%)t!Kr%AwZfx+^Y?^5KnBsHiX z^T<44;mYRBgneM)b8K$9T5jb=s@r^%mVd>~wq==eDc+B;vk%;N^#OmNqrbV@!ZFs% zypxZ>Ay&9Nz_WkQLOUUx&-c|X`B1cBb(GzomAz}DKIU}py$e(%wjS4UJm%oH{etzq z9?abz$4{l5v)ooE{GVM6gk=eb*#(?hZ)dn_pY;fO7N3_hFDvX~=(ys>$0yX+pe=Z9 zu~FGZ;y}2)D><0i0MSwUzC!{jxaQvLu6^nzEZNQ8Ip{qA%-UnD{aVFHb*EHUwo^U4S(lBwbvW5^xBc#9Sh;#;rtUUChL5~!`JkxS{)E1v;9_zPy zxo4h_l#M@wIQ1DmXW6tHS<#0%i_>fYNbTJH>c$>C2%O+WgM-6A1JLjM95u+3iOL1_ zG(lWZGZl(sP{Z%ldOZ9&e);Ef!&fV}pW5I=DWY-)`0ZCRw$fzIpgnhShvBJosgVto zlzb?brJhbn zJ2BW}gaRAh&G2-JzekAq=xbkNu>A8^2*l|ek25qK@eC@xaA%NaLBelqiD_ak_A(~E z+E+?UZ9Yo9KbUA_Y{Hxx4a30PgcS4!VIiaZ&n%zRE~!23w&zUQeaUnN8v6KZL(*eGm~du{1;H?w!_3+o1q~seQHo0v|c= zE6H#>-+PRQ$CWP4iL6cnl=iMJOeKdZF2o=={7kM{yu=vSXS4rQB>ZD)GDvXoatecW zTwGo1wHNYwpTju4YY>~nEWWq5clL`xjV)>(J8!?kJLH{FJfWYo<78&uTUxT8YQ?&K zF>XkW7Vblu$VP1Gv(z$tSTgSNQ=cd0!7HO;-sT6!IQOuBj^d(PG?b0+mfym%Om32i znezB{!0g9qi}G%{8}G5g^elJF(vG;Gdo3=M5eOv>o2d{;9$GB1-uw-`HTI9V_WK)p0Oa!ohe6kNZE1o>f`7E4lqjvlE+VR~Qva$h z+FJ;$Phvq2TpV5;DXsliz1x;Rn3wB2kW??mICXxEwzgOek|{DzKd1D06_x6F->Z}z zm>Yx%g}o^O=peyo<*o9!HM)xtU}2og@a6pw#j{ z>9gl?`JvX+b$B9N{EhcdI^v#qU0{Ke&`EA_u}B6m8Hl`O+?G{L>l^(uW94vDxw5Z9 zj%Wl!n4>e7mO#~e079r{PJs+Ow~I5$GYg}YF5z$qX0*R^h-FGWToQ2KWczRrlAzE* z^>eOX%p26|r?qv$sFm-<2~BqbXd$)Q3j~DE(Tb)kxI=eHPG3q5kDj?s-r^hqYD!6a zGA*AD#EOd>8)s0W9`s)b9a_>* zx6SC!s@y%?_d-c;tt48ey|h3)-a6QR71y`Ps6COEU=_j|eZwSZa!Ak0UjDPRQc%~i zQnIJz?r`31w12*Lw(~&g&kJ>3kQ%AzKd_mNb9Dn%a|b`6>0f^h_sqs7IjY-ba4B&}>hK?(Be!p+_xhp#k zQ)PrpN80`_`n37Hsb!P^0GXIt*@X)tJj4K1P-cW9NaePpqa0J-+Sp^lm3#HX3?QZa z|}@}v@hvJ z_n0UVmCQ%v?YPO9QxE?k-N6=m{Xtz;aDv_-{3SohsJrJ=5qR==i5RFFyCAUm;Lxu! z@$<818q5QgI||sUkU$Z)#V9rP2;ms0$tE5M*Mt)M#p4j@=Qe1372sa1e8XaU_k9?U4c4OY z1YG$pe+zaEEq>zl!#DoZ>#RQY+?1LIz+mcr^$U@187JRcZV(saiWc8YO;%Mp(Y`Li z{2&B2r$y0G^e}wxjg(`~RyKgj5A?rDe`_{ikh8-MV`g9>YHCQE9Kb1};yG;l#jXjh zhVg>lBdCZhd!DKh2>JnnO#K9v^Z}E)*%f{((}|psg8W+*C~1*(yMp2CuL@ zcMbBbGYvLxb}za!0~$~}lfZ1%?v=laq`c$7JhHNalv14LYS$w)b;8tJSxh`Y8}KmG zJBy3;?Cd;~Nry0%8LFGV_UY&yA_~yJ-5&y|by;`e{*Fm?3Twu9?*oXKrMPVdMOqEN zIGeTg)9W?~Q}3FaSbM%bB5!;Z1&=>ezqHTjtgFXOZ_+~mymkK`=COht?+f0lKcy{e)Sx*}m7Tn{ zt6;6J!P2{-^f4UCf>GCqy){zaT)4r1N#p!*P+lt9cqbj5Tt^3LccPi!^%mMmuUyGa z9%D=SL6hp7r@G^>PB-@PbOA%)lML97$h{Bc?r0A`z)S!d>DkQQGuM+s>zy2f+|?^V z&~vt29Gb@gM6bINvH; zJlW<$4}D2jv-TOrbA+Wb(40JO4+<~TY|7CzfKQG$RR{S2LYLVvR9d_p^7P#KB3*!; z7%r2Ao7X!#c6?vC6#3JtK8!n=1X$Du3aPeLp3e)uSFKJ^QeHYQiJ3NQRE=`UsJ0-=ZwWseEhPGq8-`NXK7oR=nySB1FFpI9@5cO-g^M680 z6$s^XKTGYP9}CGO9yk1vTq5u*EG4bu>zvw4UT=TcMD38?ZtU$0Qltsr&d8)VvqTly3OX`M)&9 zkWR-YiBgu@y`zNx8S0{4DCb>;>q#~dyznxVC@DCYPL!TWvd`hY;8Tzig}y$*v)VySMCI)(DibRuHR~ ze?kIYn~k3D>EZJti0J4LB`_;XTI|WlkYPhm@3GRH%~)SMU~#*xU++6Jo%K#dj%1Q& zgHWjY=$YVSSZ^%XFgdbgG$i#(F%EN@!PsaW*7Bd0AcTW`N=Z3DwmFy(N1<)&g`yDo z3nbUKjqiXS;!uh%guc*vU%auxxshre(MAi9`1e*|G?xqtURjlK*Vir8(Uf_eK?_JX z>vm{yZns5%t1_$(?Bg76WaIY{HTx!vY`x$TpGy3H1~IyPYM0y0u~cNO9Cdnw_^Fh& zF$2yVa0YL5qJ_(_Q@NmJs*g&+!8p;sKrgV{OyF4O_sF{yPND_HnZzX|{iAYFKB(O8 z^sjjih?YHN`;mVYxRqV=cy25j?*w$*fq7dLh*rh%E9~<>7|-trL=IVjr;qYME??JB zOi2F%WfQy$eREMX)!dwa2FedXd{=80X&?{ygy@ql2WKrKos}w=W+I5~Yv~3ao2Rfr z%CZ@vvf>x-pc)MxpoJ>G916jE-)B34`VkHsMr0;gj43MgjtZ}!*0Ek|>ckST$khCa z&vIYx>@)3T7u}>Hr*2RUq@=bzumb7Rkx9>~y8BXoo~l_)e_9M_?Vj$&z$l=Z;#x`8 z#E_s{`pfsZgZkZ%asM4PZ*g!4(NsREy>ct}&X>GjY4!3(L|wwgf5*m(b3I}YY|dGh zaYBPNhen`#-{0$Wc{(+FY3Ih%v46EZ3J5)=MBY023kHmJuKz&AhHNSjcdu`J?>H>3hWkw6Gtftfg4qui4S8-VxrnbO<)KDyrkkpf`=Ufj{?B@v^qf{~fiWp?i(3ov8Ec zX{b)d@7}g`BI%W%pCkW{5GGc1B(rj?VE}gu68s-nzdv`6;nz-Hcw#%LYXhp-c1f6BcW?n(y*KF zr}oNYJ_goa8_3S>5Ik-F${h{xo)jUQZ{Ge#Qd>d`4z{v>yCyZNZ`bpD5%u`wEtSKl zT$Fp{@EbiKe{)DJ>?FSaz&sami2?;eAkF#%F=HVo+zR)4k04B zQ{cdP^j){1UGZoF8gg8o{%Yn*JR{EWUEGIpBiyeHo1`$7Oxgg)tnFK-zd-%g(9f%$ zRFn0m3})YU<$TUEzCbJZyk$3JXr0f>&cB=*wuYtFcDTeIx}4AV1`Nst)p$i>L&`8l z8=d(c;&d1&ZR%TI(*pza=<-pS5S2&WXI)UX=^FYK3M#5y=ICMe_vajydXrJBQo3S( zS)>W=Esk?^UVkQUEKklsNU2B5Wq+(=mE9gq!IPwCu;1W)&)<| z2;!0*7k^0cKtK)LE1F{LjJt3fL(0ZaGqd@%!| zYh~=*SKmVKpAnJVE4;=H6ye+y`h!>WnAd3SEraXCF#GmQMi|(Bqw5{*9e;ZP9@-&V zAS^)Zr!~WZ?AR(NOJ-*z;uc7FV53FH>??6d^MhJnjo~+8~eu_2`tez|mhYYSc?kC;B*|GnZI{~(_*VN@B`$^!& zW+(ss@EkjbDYcbo&D&RO0ir1V2qNfazWNLd#Ka4_JIvO!XjZOeu9u&cD@EpX!E*j+ zGr%pj(!;?0Bqmg7?ImZd7MZeS`m{@$81pwAK%tSbu6F(!ZwR{ptuRag$8A=}?Ra&* zAo*kr7RACg6OdnZ*syx#Wo-76-~Iv_C3*JUqb}5SxLrr3b3*+lS9)kat4C~$br=bU z_d%DshDI*(-ZbbyRvTz;QuxXh0m)`kPW{Bm&NpX0&enU=t9&xngxo%bW%66=71{I--I}^0Av=JmEghn_GEm`My zS$w!fJkSW8LF`sx&H{5$H)sGS5`QQVu{{2rur4#{t|PT3xCLd++060u6z#a_3Nc`q zlOuosmWnIss@Ise1(1xw-7q``1}t1lf%ueoZsCa>=8xPdL8n9I)UDPAFGPR`*OZ852pTrgUHvr)R@tZo@csYu{Xkyzh=w2=h4T=euM{#fe zyh>>D@5Ng&cXB*BAmk|5QH6(6W3W`^U!YN_pvszssXOatm!)r!mOka>^aB0{2@H)gq)qU5u4Y4k_dT&BelT8M4GQr!00sqIm8lahO!7N>v z?YIDi-A4BawsxK8!TZAh0CS|E$>!&xx6Q;Wm{xO-*U$8Bi*36?FLWHyBTFDL+541j zV9eDVn3l+(avW|WmPiGj&i&;6o3?Cp&S%azU)U2}^Xoo~#UsB3Se9WVKqp5WLI7fT z!rk6DXpm_Hb)PW(+*MhRp{6HE(T{N8J9p4_e~rlDir#@|ds04jdMS@p&qHAnT=s*Ps=i2PvMvyFHiWUO^~fu8Co%BN4;UVk!qtExXj7kWq`$Bv@_IR zkG$&ABUwy|JZXn4oZ^!`&d$)(CDWEVwdF4g9#OG6-ngv*!a+D z0(49lwZOO6a!8r4R_XRyJ<87SP~fCz*sZlZp!pve7y^zkt*_pDgTJ)~*Td?HYcGs? zduO)4YHGzwCgberFjsp>X}T5!favK7-ekZrh(vI>oVSeyIZBPtpj6Jr;_g&Ty=$C4-SyiZ9oWhn7 zB7iR{>)$(yXTiY~25;;tAPZ3Mn$O91Lh7;s!i~vnHpOz(Cx0-M+3SJ^V-^b(NXd+#L> z2n2Y8`oHhq@4fY{SF%_k=bSlnX7=8*%Wuz_8PQXTSOW8IB=7xxWSO@@89A`0{UTxz zOipl+u@s{ZhJ*ve`~~%mil+|b*}NPazMpRK zKH_CF2nDaSp|dJyzSmL+UHN|U!sT>*htR6isYLQC&7&S5U%83$xtjZqx=)H+HWZ3=oeXM<>3;A&zj*HRnam)=d#{pz zzlyWCGIib0r|44QU4xP#yIU7uJ$-s3OuFRp*)Q6LZ{OLy==u#A?|xw{S^Dkb{fs^f zp|wKjcWbGrWwN-QS4QR?bTgRcFTfdhv*@O zZ-SceI(i=2;t8|y+K3|&+L&61#eT(WD;_#Cw#{?xYWpkZnPlxRFoQdNjsMp~dO)2g`EBgo^19uzv6azgu*&I#+*I4qJ%96u^1Qc;tO;n##i}nfRS=4jlq}rBGa_s4G|j z1v`|3*e=jJ`rWkd)fLVT=n(8W9fnx^i83Sn?f?YxQ$Cp*L%FuJb$ZX9hi>{R?0;~n zIw9Q~KS?{3A3YM%t2$10fv$U0pS-(5bJ&yPrM#tQ&tJi5N}m!@d$K#7p)10^v_&qm zWxavl6hYxz88!}wbx_BZYC2wH=O>P$HV%&i#<6WQ!POt5P3egTh(!<5noi;v5CdYJ z<;%C#CfqtV5X)6LUegmNwL*v`H8#X_7--B-z3qH&jYGHBpVY9Ytnp5oTgf>4vDIgZ>sE=pV zj(epLYg||s>}gGSED$=QuuyjBnnolh$5eRlJiEv4%J}ZvV2oP${6-IW^z#I~+SE!; z^;|xAp0jgf&l&>U&$$1{=zqk+nP8q++;`G*KXkoBTYGOY?azLUgd$8Y`L+Q zY^Qa49t(H%#N!F%db`mv6T7vr5Qc8RAm%Ad^?t3}tPIKvPoxp=G=$Z&ofF;=K8!q( znW+}{eB=VNe+sY0jp#*pb_ZmaETcRv$LAef*LI6X@f!%fImjv3td6z;vbFu_l#@LEzh z?o>O`n)$st*^2s8G{yUfWB(Tsjc@fU#MRUGhy3^UyPrzQsk~(D0U=oy-UHEd zYsKEP#E8x50vf{PfVRVtCh5_yESFe^bul*2)xAuQ@puP3G_G?5$f`w_hE2tqp5D&; zY8Ts7biX*nauwUuWQ0+Qb=8cL!{Q60ByKBO$PH4Qi zpM~A4p^x~})fJls{ZhmlC0x@bfmmemd9d5)1khc3nLKT6-Uq{OV8gdMOTBFNvi;D4 z4#C6W6}X0F1YgB&KbG3=7{35rZq(XPhbI(|9#Bne@p&EsQHnYvBeXuzlTV z2uAt4>E>vxgZ9MDsu+k*7U`;Pk)csRiv+ciH7==!-WHb61f&TPBvIipMEHWC->3pY z>Cu5~d6nsj06!s*8z`gp5e_86RC-rAaju*%?Vn`@MDHFkerMk9;?uptbHr1#DvL2_ zINXZTENjnoeI^Rmg_-E??{bo=Q-;N+PLbL9BG0s>PaEF(#YRI485Aq}c21-Lh6A6d<5wowYWY!4zQf87UYU(Y1+BJ*mI^q) z&O$P!5H2@2)Gf|fYHZW`{+eDz#~}H)#GS@S4Cfh&hSWA5pSu|v+_@ahN_6<3l#@F$ zSwC(`Cue%tU&BJD_u$@3s$vaUvQL;!>oqyQ6poTGWM0WHI;oE3cd#>%vn|&eYhY;+ zk0`jR+&D+CT?i-s5n4djuB$D5U!VlpLOr_5BuY^bkvhbl%V5!FWUY>^T{>$26{P`D zbHdIdC+I76SVmjgJJav!{q`)%2pz_>&(sP#(xp3HhJ5A7U=B(fOB)kLj;|Rzzkc5S zJ)|zA;X(>U%uoQu3}R-o7L#XgE*ei$VH{jToz5DJHfSK8@!859H^cZ;W=yj@Onu4) zB{G~c_%nUVpPFFkWnV{(cfz(-O<+whpVAL$p3%CQ-4ZI;tIWT0!6&2yyI1MUB zuG*c!3+V*&!FfH-;a*ob%YC{{bJg$;YAyYtI%LM6p&7#=VOL#e;2ULErcYfqU2noi zd(Jn8$Jn13(rjk)=G`>~m@J1Cs~W+T@hZm@us8*?CWF?H{9jX1beSfTV$BOjJt-O;$O5%?8J1MvxLS7jI+ zulEQaZcL7Nf~dIr@Wd*)X)?`KR+t3;Dm00=AQ)pI?Ak*8R;0JQ=FWd_@pBF&af}I> z-rD7nJ}0;|Goy!dGHi3Y+3-DV4g!%zj>&g9%5K%dvW?p{-%kz=gH+>af4^pcDXlBd zdNGA?$A}PX18>aGjB}&=f1?OY(piG}PFV2oUH$xD^918p%jp($jL{~1%$F|kd6+vB zL%x!&GW!c9%pa#X7erWE5r>y5dk}W?jN_R)BQIQyD~?l1GK(0?e0+CwHEDqiE2GLkD5#`x;+?xmeo_^F^;iAff){-)AuiVHx9)fsg0+X11fHu|44| zEI~uDBgVMl<_B#x=U~g{_{VDQDS4XfS6)8Lt6a}#*@r7aNh^9O{5?c!Sy{kkk8zAH6% zwj_WVkSJ;e8k77C1VT2%M6@cPcMbx1ZJcp6cOin%au)*0^?==O(jkXP)&I{j{}&5V zQ?@qVDZDdt{|xVhe0F!04+P@eBEP;uP6?FN_F`z{dQ+-VkUc!8R)V z&g~^4*556rp}zKvkJp_IEl#5g&W!jF^cT5;M9sLKRdjZM1e=B|mNixSj+-&|2A|Rj zn*+@tDKd$^Ao@03o+js7wuo-waHvJYW9D|~i075Fc7x-(q2W!WlziQuyrefElh3Rd zUXPsTp@CnpTGyJ6%3xxou#I*{N?J@`urvr8`ea(JVengGe(02%jJkJVyL82_P-s4W zf1B<+t#2M~}2_#?A;ogU4l5rgXMs8c65`qyOF z@Vn~NzA-JgSv0z>7TX_3`G5Z<>pvc47l+nHGg_#M3OSTbN0*m1^PPpf{x)Gw)+DQE zZSy61D6Evzq)CMSQ{1sd!6`}fjbR9X($E}JE9%CwyD>ESd)$%HVc`wd_a2rg%aCOv zw=PGpm}{P>FNbBpQLfbfXJW#7R7_#&1=}UHAKVs~6EdhFK50Y9X|S~zj#Y3ywQ~K>10Jgd(nU6DCM;pzx<^}%ZKsjwUHfRF)I00Z zq81OgojP8XMZ0}2zj%)#3YaMU6pq}fmcT%ooG-EConU?-9Z!m3(UvKF3$Yp}iH!5j zU}D^JSek~tTc$+Rc>802nOBX0pRUPD&`ZcAuk`Uo#SX%P(foG)@x({4k#S)nkmR0A8umw+9)*m%@gGo`6u()y){R!iU=;4EcS*3z> zaUwc78Wj35Wgr7D_701HIl2PV8g?dtH8T-N#xt0A=*0Qkv{!-5iQCQTXq26$x6GDk zt2qBWVfv_KwJrqH>H*xNmz!3i^tl-yBLn7hCx>L)H97?=LPKFc2)@q?+qJ%K2rA>I znhk3_=j^VaiOa`DAwKH%-nU2siUqe|$!^u^ovkvL(>0|F$MJfu={SpRn34l^#0d*e z0g=a}((6|<)iV0Dl+;u(K3?elV4rOrSyU^-a+dQ$o#d!-XU-$oG!f*GrPPi8orvTH z0!Brb^;Dm}`IWO>k5ojCw<~qfq{G?Oz!}YD-~A?)?#o25>8p-$X>RyC9~TV9P^1ta zqvB6mRFuL#GicPxCc^m|B)1P|djcD{Y+HeIpc?PYJ_9Klre2>|)jSh4fXJ>p9O40f z`f%sb2q>H@05cU_w-0LmbK{p&12EveW;y_gF@g?E9j)Gj=zFZK9a}@oFAU!ID7n6| z=EC+r?ZGpv;*(=^wf^g)we41}(X5Q8?ex~qFz`J)M)Yx1?T= z-yB(6hxq*Di&3|4cl6{Mo{E~4shu<)%)Ss4ey-v1LWPEHYz7|!E7EH0cMW=R)vx_> zn8s&$Z*zU?%rR8>o%RRvTSJ~(m17NZx5XO5iI=wFO}}L9{IdlE>Y_X6QD-4h{(SOy z1N4~&pV}yb3^Fk#Mb}LlZ=l0fEt{QP{8Ph%OJ*R2`GhQ&fis|eyG;jXJ0R1NSddih z#p$=rHN<0t29}}i+{S_aEL0Pp0)gC-<-5HVH}uLSxQBE5hsE4^33{y#^53$87~L4c zR3Nh0>H*9_^CMIr!r(9=iZQ5U*0N1uwtwBiZB-R%QWhX{joy3k@(NVsg?+*WQGE!6 zC|Stg^$OY5woxnkED@#lm}&|Vw)s}a0oktTA$`;}7I91y7j3|bI=wuX`RGgQ z&CDb|r>yt{*cMV+9bd@3@VG~F;|*|W=v>HaC!-+9CVmw?wSry<8B{mEyVw3(1Ul3ur2$&9f+o2NjSXT%KFY+A_Q(OEiPs zS68(3jS2f5BN&yZ=}$;(V9m79oW2v9#WMq}`ePS*ytRsb%o~r#r*(hJv2}NduH?Ve z!^X*&Tp-w|;yG|N5ThczYTOyY6GXI{HH3T@IsGBEq@*t)E|x{FfeaIfzG&yxP>Z?X zp-g-xCAz_MJ;(F^d_X&W@?Oe`x@U#6=@ep%hKpjx&_CGaT98zKt4%ULp=q}Ksb}@z zi{v9s3?}Ni6q3!yi#JBS1WKjq;pxtG7pZaNe=;a5Xz6uWf7DoMtTeDJU3H~y&y*B- z(Qa_Mu-6a=Vwc}0Wh2t-y7Cdc&=zYYZ0+~>l2BJ$n7ZAwtW{5umg4Vwh}RAU0h)ux z3EzJLuEw`zKE*p_mgZw_O+0vRfHC#0ZM#?|(;w!2WxBax3mqME^WEMPE|2HR7@#Q2 z9`8MFp;F{{F+T)LH7v}o#2;)wR6Fc$q@wukFxX^5Jfxnfr70# zSL3Vzm`h6tn(f^o`T_D!8*sL@NNvzbFoxXeis`m;^*zGK6El)7HZsiAU%T!|p4hBl z{<=LKCe$Arrs9?D;}xOt=t4x=8Dt>x?Dq5N5Tdb$-K*SDj7}fm&*|p}KQW!KK%U9L z^zzczq!3&^;i>#3MWmK@BG&1dU|unW=7e37!i97FrlwV1)9l~%2McrKkjI}ZZa8n%C!RDF7|$E40DA+0#K7H$e+zqmo;kM#!ef9^)am8Su0GOx zh7B1vKcxh(_)JM6_Ul7_ZnNYL;rviXoi(z6_JLT1%iyBbw@J?j_=ThPOOl?S^PaMF z!~_oQDkbOkpyEChwu(Lm4P*8Jpf^H#an4OOv<4)&eoo$pP69POE8rMa@a(O?CfX zy(w9X=}c|Iev5PCeB#gx_ziGb--wQc!oNDG^V&4vh_B94=o$+b1OARX*I97YI1^X% zklzT<95VPQLu9V`M2opY1swTYTlmu?eTz9$`YQ%;0ImC9KIO|NMA|Y}7q4A5u`zaV zv^O!Z{__)VXmRZ_Cm+v)rw{)86c%QG<7R8ZuC8DRR)uwBS9UUVJUy1SHZTQmUzi&^ znmyp)=Hq04X<}|_=J|EIC8v8!WyT4VzgCw49xg1^|P&a-^>`TYIewcFxEc~YyDd*Bz#1E$YU&UW_> z8V2|eQmQ`lAM`L>cMOZ#KBC+fsX3bREf;EgmtoJ)+2oY1EoeF~V(QXF)4^;CJ3glT zUkLWUIoyZ-Y#9-q9)fPBow5P~+36CeOk+C=_S!2r6=n#8`-0}o74(gt9kyaF>x!o2 zH&3M$0x@fMe0=vn>d7p_pTkMiD@*mQ+HKM?Q}g|lQwBpIPh&4EFep_Db|fq~ZTdzT6NQ21|EUt;_BUswmMJ27sAq81&T{}l2Gez{`JAB}AEXjRw|7W#9p zrYS+F%IwjWC>52{Rm6YFWfD-bzjz zooM}eK0(H7^%BQx5}HHQmD8e=6R9xG<(V0-`)0-$NT@TF(wY_iR6!$ydEeXJZQuO$ zA=t`7=&d9zGqYt^g2eUf*Ciz-tw)Noq!mSR)qnV2Q~grTb$WUE9u*bqd^(Ls+0_aY zaNnIfckD|m;1g9XEiJ5CMUSC>THyJVr^PP{d4R`Tk5}N06u!MZX~kgVq@}lZb~1G- zc+9&W=Sf&G{8!;Azb{`fxdwGb@QLHRl(rhJ`A*cv{5(CIA{@SPn_0E@zsla_nevN^ z8|zMzaj>@+o#v)^9TpQalA{OZ;^MON!>x_*@$jJC=cIZ5GO^}RH7xcnC8f*a?}v}~zv%bFmF(+rJhx6~$+4=d7Sb>6r zcq$qi6ljE*4uu5bj|{kaTl^xmv|K@34)j+&JZpAUGUz^IWLpE>y<4|JLqZ-p`Gx+g z@l*7yIDMGY`l!Iehf_qI0cWV}9UNw+r^}pHK<9{wKXDi}8pB}AgDAouW2SEl`d3AA`R43_(Fb0p#rS@l@Q@(-!T` z&3Ab$-t6`S`o4SD-3{iJe*IVN6TpubKNdk%+S;Rs@z;rVL!+YZ-o5(-ylrT0-4sld zb0SmN@>eQ8Dv`!tr4iNcJjo*Qe5$CZ_$o4+poYzN7 z58~rm!WdFgQuw}K#9un)!S`B=9AOF$LveZe>k0u9KW|Y|W+M|}PIdvYc0 zZ-;(A1$4^DSgCNszLfu+YBf@1y*ilJ*w{EfKQH3G^HN?O5oz&PhxlAb)o|_xta|_c z+|h*5Sx*QfBjcGfXY5Ny8yjKEy=fX68XM~W2=$sBy)ks@+BG>@+0nDy^c)-SvIvH!S_3qW;OYo$kG0eTA%a2?(d_bkt4&y$%%<~H<7~sI_RDjF9F+t>TLC$ zaJ|tgqEGXaE#l_w^5I!v*J5a-sN}_Wv{heK;hMpc+LwAx??_y@zi_}RU>Hl=)cM5Y z_|p%I_$u79A5W>DIu@R3LZaCxdfPKCZ5P*?s_*4yrln~Fj~`uC-)u%2M#5}xIGnk; z`Nzu&|8&T%1mXq4uqOXsTf84{16mM8(ET0T1lkbPSJd5HmcQ)ve2Ug1#^yC`ccyqF zlyHRLU!S0n)%yh1Zy~L9}@LV*vnydbgffT&Z2)*Cs5hMlx7e; zFu!y3fdujGo@5;8jqLNGj0O(MkwfC4;h}*1Ea8ge4h`qL#Sgttm)jLyp(+I&X1bzU z97eU!H>*SLrg%58S(3VpmK;_Fm58|@9wEvtZ%;JZ$gbQS6w`ib7@N(i8K4|ny(_ML z>mOklvd(-S=1%EweLtJ1>$t$67tf40uF3VOS&!-2^P_NY3DfHwcdg*&Rcud_3W`Cj z&xc)@Wso4zW7kD@l_E!WO51{Uo-n%|NVccBc*c`=!=HVU*Rj8DM&q|mczm*a^stV> z9lesv#)$1+i=&(juj+|=_YO*N7wNG%it&JcR;CeE<~A5U8y;5| zszP~%h9LV_qaFOtn-q7T8N;`HqTD&L6Wk69JMVHNctL|XoEQrqO+$|+tPXAXnR}RU zYMea$X*1fBfA6^qB46Jv7HnP8x}RmJnjOLVxwN#q-)7+lcDGdlh{zc8s&ZF3_IK$v z`3dH7s~(}$NFm-YO=DnEl>9QPj}NL56J=mv&f}%)*b-KJ>m%r^)Ybdry_%(73wiEy z41m&Pwk)`~unif!e=X>m zs9N8eS*5sz$ePx|=%x{7N3&8y*N9|gWtBP6nInvzn+0HZxfeff=#^`d|5a$I525%c ziQ8dZeAF768UdF!l0qXj7rH1=3w}gYaWUrf50&sOm_z6}=M}p7d9H<=-|osS_+O@A z87Z&@?N-Z>g$^k2A;Gktm+3>E9imnwYeqQATju_gR*R0kB%uA8a)>2@ZcFXb2rlDD zS=+d>BfMr-2Bhx`F)*pF`M#WEPi-#y`#ggjx6LMglJ=(^AZ+PQM^77sCk zSF)2}JQR&FEceLZl?c|gq)HjoOUfrb%p8jPVTuUVv#pjJai0GAp=(QNhT!=7VxCxW zyurXkkO`pswGn5(HK2^Q+0Xy*G-g^ge~Q1x@zIgRkxbJ8}iQaMsT>xx8rjLRV;FBo?GARM&{ zwUg7hU25iK|I#T&&@^rEhlyn;77o>rV1nM92pwEs8avLc7juzVxl6`^TcWs^U8KVV zULoEN4=c#vH@0h+Op9ioQJS@=2?w^BnumisFk^iwShUB=kWE~+Fuj#njx!A<`^OLuq*I&)SbS7H;C!c zb`{I{*F83)N8?~4w#d8OR+*ZSKtk9UmD@4a--^nw>wRMqLM#g_7L;nqpx2b}(hJ$) zSDwBT6Ybg(ovX2_Y!H1r=ALE^+T~0w2)BT-U6*bVe4^se<-co4Of0p)H9!NjN;v8& z1;=x%y|v%?7hMi%(LatZsOI1mN5BPb7Iz!-zBl*t-HpoLVD?!BBqjZm`&;9PC)}BG z-XJ(#TJ9mW*{V)xO+mk|``>4fA8xIaDFDOZCe*#JJDNW&8tI`h{6uAXb63mW68XR?Tzk)^?c7!*EndnVS65Bx+|(#cjj1+PWuX-{vVVy&&L46T2*inz+B zufAUj@2s_j4@p{=zd>}<@fS+>d2tt`Ud}T-9}}w=jV2Kf2OXs;1ygn40rb}!Me;I^VjyGA;IpJfAl-JQ*-;sh^+z2Q zjnb;B%CTle+q4O=s5sls?x$lvrk?Wce>*G~tB5kU7d4Vo9#wFa%tCYy#P00}ft*(rKy`JSi6_S?l zZZ#W~y@qzpT&48+^nGjlQpGvt4=2=<6egWVn73jr)z{`n*}d8u|GLX#sRfpys>pwMuxcy z&8o#Y16IeaD7G|TrN^*=D}$*mDt2MjZ!l=T@IB{JZWp0F9M<5U0`~8}D(+D0*Q+QS zunaT>BVtF>M9rzAU-#g7^((g=yOOEEZ=p{^abF3l#l?N*(xmBm^6ec2Eg z7}%kqPQTmRfBouaI!TWhkPXzC4{QwKahAUt=ys|xsFdvL(5I$M529xc#5}`Ya47V zW)`AH+!iZf@K?BpiUl4yRRimu8K-vObCJ=8G{97Xi`Hz$Po8IG%(lQ$U!si-Ey^A{ zD-RV+^tl6h@^7tQ@+;1%F8wg~F{_-r8cD>EGa@92FWhiVnzcj&5fCptYRUn6%Vs@` zr+}8DNaKo{YIZv^FLgiUKt=Ik9E$8)<#HcbEIXv@-JD(YM0?V7WcGTNrpJNyZ&&`S ze|;6R?uu(tmX8yRro|9Sdcb2{xjlhfCABd$EQ2Xau9dni6-+R6Xd7EuRX93@&Kv82 zSYkPGP1MG~{Ptj$+ENc6x?Enjbfi7&gWfaXt@qZEj^U-J>IOoLlADe5hXPaq4GUl% z_yA}`mb}svvM?A6liQ)T(>%j8i&V#$jm6KMwcly8Ye}3S*x5E4>F62RaQ_gI#3;B; znrE^;-FMk&rnyVmV$a`!&UCfF!eY$3`6VXx6=+A$?TMJ~{*Iqt_OcG)4N?+dwa<-- zp~|GD4=-5Zgsu?O=V-eYjf7$~)aUME?+Fnpc0j;@iR{g{xbmdLZBj+->X#;5kUS>3 zJg&qw#W`}n`R$m806&kiM;+%s@+1ifn=7r12@3WjzoL49Ln&TJxmQIaU?ZtTQ|%_x zzbfdd+iqKci@PTZvj8HI!Ix|)c@FeWh2z(Tw7G}ZF!9d%q4}%++9S6Cp!iEX1XS#hGP8q8UrTq)QALf9o8)Q^^l{nS3YYZzw^v?#i8CP;2Q?I zIZ~xk*lPVo_Ev@LoH`>TjrbD%>^_nN3VX?U9m&SwrBzfn-3@l!71$@Hj8gpJN`cCO z&LHgE=S}VmX6w7Nz1X3UKJufd*nMYxVQgG4)(eD2UQL(lX#|~@Zr;CzczTlD50{k! zjdCOJgj@2$3b(eu+~pRwUf|fG^wZPx4AZSTHe%=uzn2n3NGyx1+&%S;igQk)zbs9+ z0p*Zha?AbWN8)qNodUMW&bWWbn9`1hCkUpu`8L?I8Gv+1^ohyf7IgF|A~}to@9em> znX+o5Id;L2+mKn)12ow}^<9kN!gcE8!wxDIDX?mp>g5u$saKLvXEKDKY1wW-1w=&! zSQy4~k!J=fbciDIv{y2A1~w3p4wLQEDwOqm0@mx>=i8=>7N{$g z(h(jv{|eG~MWBexpJn{-zSMi-P~6}D;g0u+{&$$kB#j^8J)z#m>UMlm@r# zY*d;eGwIbn_dUu77P#vx@S125ckf3QA9pBA%o^Oq`UqCD;)(^zuN8=bxIFa}Qz-_s z_M+t|Rzf+ib>ER}YBS!xPE~$4{ks`y3Om@n4k+d(o0nYr8nm<$F-4*mSol2@Grx34 z{Kear=YGyzIdQbFZEk)oM<3=FJzf2!B6E%|hUG9|s8#BA7BbQ>3NC3sL-7qtbjg7U)?w-$P{Uu7Z-Qr_#!CXYF z&V&=`z{Mwan=DKDHA$(qjpf3PI|jLS{`3~ZLqZg}`oQxC0mMHTBRJYTEh%a48>4b} zPtP^}u(RWes;d3_TQe$5;o5BQzVz^t*HB7alOX+78Ue}a2 zx3p-WEy4k6St33*ItuHI*QxvfIP?d<6^)AC6i<885zS-S6hw6)R^-fv&2XVPQ}`?G z1Ox)HGLVyVeXsc+b~ag;DlKo!sZjvK)W82`!eI6WV7_86UewcB*w~2LPSyYtMYDlm zMu`1{$?YI{acX6{sroaN5}0}KEz_-^dg4R*rqwHK8K#Iw{@+9oC+z&EKej3`HR06* zv8IaJd;EW8=GiH*-P_B}!V*Xv|2+?Y?Yq0X;Vs5&Y-|qm?JcdX>0=oRr;!#MAB{0e zX^(qqUE6$#E2T4F+-);9=m>;N!0ksk98@tnM94<*>b;@nGtt#nnh(!c0~rqOC+^f? zUj-4%giAf-f$>i*TUY6p%7e*84)8kLVZVr>NoxfA;Zc)>)si%9#K{-Vp)85WK8Fak?Af!L{wysXHOZw8g;vzb%}U;(+7^@P zoe!pPVa6w3PCqt>{GAv(*s?=@rbLJyRssYEQCsO#V*|o=`zn5i(ply%dy@FwD;F*L z8dtFF?3Ox{KZH)HxA4)r{2SBZ4_f-zk~g}qamz2du)8fon9^SHZA zI<>S`4$zgh;_5P`gXL%AyOY0d!6ty#0#fLpe_*slhP3>wed(u9O~Yu*Yy4_w$8}!4 zYW@D)7rY$~uza60M2X2*U~juq;4oHg6B~n4eGO0GQCSpCxZ%|-))kXlvrWzR8>SZk z3{;;-yq#TMhF-llnzA{i#VmH2hR_R;VN>z}9Vxb6fPwND^`~eutB@wMz7BW=l&j@> ze|L(P6h|UJfD+~-7hY+)6-g3Mevz9FbKpk(w9niBpml}BgE+fcnzXsN?B zehENRdHD|i+sv|Za(_}GrEXZ**rCiE1MtjjEUanEIB~P)I;D2|jz1P}AI7qKCIjno zOb9Mj%;Q96>Kq11kf4PlX8Vt54m~+ve*1D?M1mD;xTsLCH>TzOSxmJt$&AW$JV{99 zM3dEpsy{yyIFVp4v&fK;U&E4aGvg%Dl_s6uG(zS@Peyo3f`|VNt;r3|DUj)6(<;iu zdC2+%vk3?YJbLs(8`a<6PjunxO9h1->yv~u9sIV*z0<9z>P2M? zZ|$~&v32-ECb)F~a*akv#S#NXdo-tq-(c;?z{%3eYiqPf`L^>dT3T9=XUozmUiQue zvAprVYu;F~*g}AWX8aAUu@`m3Dmk~ifb~vdVU6(@15rj;dZ{Sgz{?*1$5|6})I|}D z*Qa?vGO|>w?Joe3eZT_1!qa2|r2ZjTaUm=nS;{^kY0mud+t<*4Ni2}UVumGyeFs^D zp8tF_zhq!w0E59m{>qn_L|#rVYhViC7_(7~eM8N7Ed@Gk7$W=+^aG&M2KICZzuPN? z(2PV*sB{O1(vxpRI2283q5>k{)~!OD&Bc5j@p48n`vjx#sL3zP9lyVXLJbZH`HKNH zK!-%FVu}^h+uJdGNr-TGKjwOJB9mSq4~?dR zB7|Em-3!mm%oK2#PkqBws=dCj5DBtzxq={k&#ogk=0t+f3 zygXQ(h)hBU4J+*EZ5`M3N0**tPG>S6)7C@ zqmFDACLdQNsjMjPb}E3FllkLRS5X|lcEKJT&DOFG6ve!5gI6DN*>O@2l3(k(rFUbG+m#U$mT z(wt&}y8ApHktKqzdijzG+Ae=thXA>ez0~s;feC3-SPQ+Z*7u@w61_Jk0>i`60L+Z$`D-2s zl-y}_{QUfag6=%O%|Jd}7RlK#I;#ES_5R^uQ&Us*VZAnp8;++t>kBK{Fk@wV%P!O1 zaY844LTr(qJWd@-YI~|OMz_%8;|a9Tn`VKEPGkG@L=_YF9I&9=xKFb94t39hM5M6SPp78|A*M8{yh;PCC6EY+bSd^0*+<2o10tXRmWf$aWgPE*Ox5mt`TT21P^-68kQEB zM)e|5Z{CQ$#Ko9ogblmmaf@Rv2cvUb^HO_@W1Z{|p3oy=7Q4${gV5oTq&>k9-@L_D z0hX8XDBJ4TF3@woJR#2F=|;^a8+OP1!YXcY`H> zECD_kAkq0BzoMr4ZB#r^u(8_OI$DLiZ@4%(NKLM(zvku$Aqz9}kTNCe2dm89m~pgo z;?tLFOYRRRnMAvA8_Q)RCnWnmhn6duXd$E0tgfl|NNV5{bd$2;ECW&Vm@z@)9p+ZpwKZC;V}DZX+X(i8HwusCKBcCFw;MFiBX6I#nxT+O`?;K zm^}HVe8O}MO4o=C#W#HTWm-mjnp{=JE#gD#*F40Byqa=u%aHi|8=LQ=;!DtGM|1d4 z!4#c?V)^H_l9HE+?vSzOdcZT1`vvr3L2`WgldUcrzSV~Zq#D^Q{QXkSSO(qI)8O(r zF(>NR{=Z3QYpgJR_=pbdRA`>t-rTe$l5YokWO-z#U17Ozr$yo3Z}7F;_ZJ@{P<}m4 zK&SsnLvNZs`jeLao%;XtB#?>ErJEsK5?e6^k@Z%ZCBg`a(TG^~j?s!e-yi||IDE?* zLp37A+uedZJynz`Y%9R?U(Ja_+QUxMo6&-s)^>w?Zd3Ri)@ zD*rFX>%Lx;s*E4{IRJ95ioMm2he<&ki(vrh@d~Rt-1m3VN>Eh|;<9nT{ZKA`75}nh zZlzrTWDJomrH>e`H$n&H0ulxSqFaQj_&uvKCYkCmh@1@S z&Wf%U#kUMm1{WD49(I(cF7w^e>uq6nY1mJ~d3)ofd5~}KR!n-NYbf_mp8uyJ3V=Tj zKr%Z3!%-2H2ecf=v$F>jA!OuV7mptuc&olX_|hAz27>9G&0P>k5QJQGD2ko-LIOO3 zZ$D06TcfzQKEUy0p@t$Yt$3Y~xQeIQY7syjzx_$y-ahQDDT{Tu9vcsQAb>Z39b9*C|l#UqplTU|n2J3U5#&j@~9q-EH_tH#hvTVx)Yu3R;{L7lvzfgs{2z46j zwM9XW1N~nO?_NcjTFhUgIe`dC4b1MWBz{AUp=wflkbJ9gqj%0_3Oa15+9=BP?|Mur za`YEnfA}LL(JlWl3|AF=vwY^hj_@y964-*;?0C9-C!R(RNZ#LYnC?w6*3Qt`Yr`oTzcvqMI{hHIeiK<^Hu<0_5oSm&R$)z!*Q|0}2MM;~b zbf+oO)i@U#LFwoPy#_y!zB130=-}a_sBjW64;9 zwSSX7J|_sZI`aO?E*7n^KX;R|T(8_!wyU?l(l*N~@i?*aWF}jTfsBmoAqUMtk#ti) zr=1^#zi_;FP5Q@_occY6r=7zcdMUD~pFh&#LOe{(l(7ZHq6is%`X=Rkirbe1pl@>- zI_Fc%nD?W`!R@HO|3jo0O=`_`br&8R|Q?_%>6 z8wv{Knn&<;6*}AMM|)JC4koXSM5DMWhTctVOzsI89SPlfe&gJqKkTVNq{w7w}OOq@^1q2c$$odgz7`5b16Zk(L}$KtZ~DBn0X1loAAK>F(|v z82mQpIp=xb_xir?A1^P*U+lQoz3#R4Z*Ltf)%H$vCD7d1oSeO9bH}7TJ?uL(9-)3R z(NJ5zGpkdiL*(ek0NLtOb?BeG&5MNKyt?poNl9HI-=`cmD|SvrIn{gjL~^@c=d;>u zdeT*LrM52?&XraLkNsSNx$lXgZ0xJm z%0)js_lNC`DtVuE*DI*kU9}^~uYvhZD#~`&2mOgNhJ7XPUK)x?Befw+aE%v}IhpzB zs^_$)Pr7EBA$WQYJE@x`Um~v+l?O!Fsk}3c1f4^8tme|ZY*vq}u=X^naC#7YZY^u} zc9J7$$y{BDhdsK3!gIqx;xN#g+o%QpX?(f+j-PDy&EGnGy^zcmHr7;E6k@J;H!O4e zB6Bv|Thf|-wrINy;IZmIGQ_aOx8frRy z1!XIEV5u&v2qR!1* zLk|;o_#@4W896uVIfdhyC=_lw+NSV=3UMZ-lsfti8o`<7`QN_9rl!l=GF-+~Wr#e= zIlcGs>KC_y>2BIg#sKv^bF5c1l;HH-kh(kiiQV>wBmyO`$*Rf(FJFI?Sy>s{oZ)n1 zxaRRBV0^{}Jv2?!SKw><3QUv*`wE8Ok036sKGv?S8wB4wiQTqWC@%enrpC*c>LTz< z0k)m%z+U>Ctj`#?mjHZy?`2)n!$B)?;@lriV$XJJz6VQ2G<}7)%W^XwLEg;dSUY~4 zUGKPiBSE*6)1TGIVLM6?_Pz7zd{8QyVsxlY?#~c zOXWc>iBvfazv1hVsbT53wzPM5;2;AW=3%$Jr8<4)EJ#hH`57Qkc4_lxG}FSm)q6@} zJ&27>Don8fhRpRm@9UJXG~N^4Qdj=3!7H#OHLGstI=d}OvSW5d)5W}pyZq9(&!`C= z`9kaL9xs+WE0!xw=P^JLi!3{Wkf{2yznA9ctFpAL!wM0_hn0lR42P5TrQE~pIEK8b zO{D8rE%k^>(0o~7@bjCd8lx6kI-S`OO~~SBf}+8w;V-U zyGhSa_H}!^-X0zwQGgg=d&x&RA1XvXLz5PF*_}CVC(F~aW9TAJ{dGVdp%aTPVFdp8RNVxV_R!^1p4&&r`3S* zD>JJo*PF*#Nv7wJh zcRR3GJEacpc$cj z1j)RqSmR>4-{@JQr9JQvNiCG5b~_Q#i$n~9t_xSh`dx{UnY7CNL8Dso<6jDkQ-+m}Al6)S?-L^@NuVYZr#eqc=kkK$ z@jkW-rMZ2$?F~TVo|ibr@|q0e%5fD#J)wzU4zTf5kUZn@e?F*|7Gge)havFvWX*c{@Z(_WpFH=dpfaoyINx zdF-QZ3vh6wDkhWLIo<}PheuS7W5i=<~8Zbnzgsbe$(Bm2LH;h*O zhw#zU=sD2hgGxcchISQlkNMXig9qo`Ph~`T-2cBb@?JEXDklvsEbskhQ+QCZcH~Lk zA%FQ1xrP)-Rt7qoFdpUzP_e0Anp2UAp7;e=(CM_ z)DlM8Z7T2_Jyn_?yq8@5z#Ew=%1unBnKM8N|FbkUcYaKUnGma6`-*?r9v}394=!hO z4k^kA(3$KxtL4Cw?}Iht1aUk5VmWDv7PB_U7{EIh^Wx*9grvPuiZ8H~r~>V8Z0zRq z{G@K<S~|kms&M)|VU){kW^WG^Z1&oWq#PZ#ugHlB@l11nrH&6Dcl!Je?_Y%RbZ+O5=PdF1_jc&MhbEX!y4(PJj~UFP+d zBoVpU)+YB3*;I?f_O1I5wO0<82zfW^guu0WO#-eM9~s3QzdIw@vEC4)NrMjojV6W;-h0`~Y%Vo#;V`F5K^9^~toHHwu%Fog{@FZLcppJAy=w!Fe| zXfPCG{Q>?PQ_tQ(Kxh6Z_)9NhgugptC*1Gt?xq%r`+a@AYl4-e`GWWR_s-wukFz8m zMxugE7OF@U&Q5Vc>2+!QjOf?WwjkkLM4S%PuV)<0sJoY7Q%LbWaUTsWEt>N2k3~>i zEBGnQNNzXcqpKqT-1=B>6U^A;aQLr-vp@?W0eXk$#1eX5`|1(nuZ**tmPd+XpX4NQ z+{h$mAbNifkDaEj84eAKY`7%X8`Hu1-{ZI*9#s|bvC*5H-ewW>LW7dRLdr6B_iyq3 z+td%qGxLhD&%>P@G)TdyH+*SpwMosY_%S=R_dVjn0)@f=8xIdZLJW?%ES$-4bFVAt z^?dHPZfq<}I;5Ah>N+=7&ECs(`@I=>s#D6s&74Oci3R*DJpGQP12tfpbO{Voq#rFg(|ULVw#j(>7Nn0LIm?`ZKbb=% z>pm$t%ZbClSLCUE+~R>$>~IEI6FxY+9JV=~6l}46yqn7M53LMk0X^_&=JSeiq!}m= z{YP(F%SJFFzM>aT?(j_7ANQm2t8ia_2Gt%xCr(62nTNY^qtCBq#-5Kv{Uwu?G-kyQ z=3eN`spvTebRuxF*Y`EJh*c2$@Q?&pM=@g=WY~QtIAycqucMh5YZr1NmpcVe0-VBK z%=Nt;@ktN$g}p?X#Py(qS&;orr|M*XXBWMiL@C%+|c|n0f{^O zZdUP3{(B-1_moCIWxhV#;&=1Wk7^W0Oia*BDTqkn4CEKXSX|f^dv7#v3(LgmO#Fd^ zvotZdlif>GZ|JcYr7FDK=2Guljf-p1t1XCFlab4{%znr%ZCUZtgo@TYVOslGk)0?X z!__+QIiC`G)hm_-D9v=SPIzTyMj4xJpbjhc-Iw1be{mFUg7lUtP}(FoBcst*nM%m- zCXNG*PZg{5Q@O@eO!v_oTcS!r|1Y>lJ=nRCd2%r4XMUcNnz@DcL*x9%R|}&O8^5#a z)^adF&qc+W9pm^;1s zI*Pvy!=r^UcZ#M*bF#CaK*+G=R$yHuu{_bm@w>k{?VzJQu8SlE~-=vA1wN=TAZ z)r+)}JMGJwT@#4Gm~%%++8> zp*c{@&l4D@Ae1(zp}3^@0~CWlJk-GnHY>3FDZi&rc|OoDir`0?(Tc`D=HxUtv60fv z3tEAhEe$x=wYe!2&lECro+NYnz^tYUFHb;XEGs1~Zg2ECWzpyxEtI;Tc%iPP+~DkO zgJQiR(pbCM%|134j~Pm8O+@@RCZBG=1`!JR*Rv=^P^^y@e9JGp7Tnmt9JfT#pAz1_ z3T3^KYT726^cs?rxf6%Piz+;3Iy-+15i}Na-Sf2#LzLO_zHBFWo`#C_veTPE8t;hV z6u=4>%T375_BZ50C=wFCum0SmAfGKlwQ>70-dL2{R{D7mQn-}8yZN{9y1^O*b#~N? z%Z96%`1O66>1}}4oq|czT5Z1mr?{a7Q{UJjG1rRg5eSc+u$cJxveNRe5$}g5P*Xp+ z|7v?ZQUCcil{|59DZp&=(91LL<(PeM!FQ?Ki`uP-11iv;JsdRkj>u zrTuG?WBLCmACc;ESSU;+5oTNqQ0bf>i$wsn%I%HAPR?H7?AR4Os|9ufdyRuOhpz(# zAV(T{v)~BVg6zWRw_FK+mPfsmAmQ|Jyn0M^bz2nQWj@xUxE2hpDb3gqoSpk)d$lJh z_`Q|iG;FqH^BC|)3{Gwq)ih>CMl_f#hC>u0zZ&tYuLzv6!^(|#(0m8}boh1X>CPwK z5I=)>+tQDgmu@H$UTSq#C%lfg$&B@-#^ZGV2v=RCY_}CZ(~FxsH`!I^?e)LZ%MJFX z25F?pu!4AnV+_9)XKadjn5Hc}Ly7|3EVRk1;iYPtLHBs3!+bT5CH}>3k!fP5eQ5H6uK)3-i zW>w|sQ)lH(v=#z5LnqR`W3VLzQ62HX2@gd#rA!uD#L-er@uM8}PHeO^N)dzbPe&(3 z8(welKZ0cUH~KYrGebA|Q@h)IVtsjv%CVRBAdck+)Xljd)4|x_=q+|iYn5rX zSk7&&w?e8lEmAivT$|cr;M1_>r1*Q;CE@cdi>k|;v+g?GPMcJn>)>u%89IeQ-X}&N z@BCiUOSB$Boz-@P9=;^HMtd2x*0ThY`C56F*Rbwtum59&4C^(NSYo2E@hD0B#)@IIxlat` z_$N2|h_u3U9v{WhBa*jUUT6fCWOOdRVIqG{uBoXH)+f!n1l=cc=s3)bXI3;vDXbVu&=ee{Z$MPH zuXE7#DRMCFVBp|e;?8wQJnh=e5*R$)p$QMZ&9?f|ZlL0f2klLiG9%wAoqdR>QW=Is#@Guu;A4I^sBpRhrw9!f$MT7P_48qBhWaOJIY1GDF%^C;qf@FPCh0)i zmRHN3wclaJrC^62A)qzye|)mb?l^!jp|uL)b|s!HghE7KiFs3NU?5{BjBd6k?3(#?y(!x)z2`A;eeKXG zgduG3a>+%Xu5VH7I_9wHGr?ud_tISy0$pua?AjkCookBffv;aKw@f3&vDPO=u0=nd zLR5~gyTu21P9PszIuvdsQ(2tsvYXLB=%M|;8=+BqgINq`$T-5+`Lj~+Iq}9qMwS|W zL<0VJn)&qQHsZ<4VNEwBGqrtgHC#59UjHDHyC-;|hq`!7H^GroWz=R9Xi+ymot=Vq zAN8*g{0As43L~Z9?{8$J?*ENEb1aINM8mA{27VKXj3Mo;_gH!UNV||_SFi+{A%+#C zgIyjC8&g;_1pbS&msgD7@2KDaEF{qhgs@R{X{V)KrzbIAGnxFuC&bNXp%B`DHh9nl zQM{&kDC5n&4$Mw*#V!}R>h@CK34EDk(SOMtiH6w~(U8}JrR=UH;A7lG0KKClScm~W zJaz21u~w1I&VS6`m9pa*X#6slLC1 z56QN*v5WY9)44QS%IK$qlsFS??+^IOyE%TUts;^7oWq6m4{Lik15KZ0U}AuY!!_?yYa#oo=mUG-NROMw+m(#1 zGk95_BpCB=+mTwNek= zI(L`FrkC+I@HA*tOoH~heZIYoVm2^L0(n+fm`NUDi5@)Ed>POF-BXI7YsHzF{JE?a z&EAmCC6UIQSmp~uhDf}h8Us&Z!zK1-H*oP-K@3XuCSu9bPd%Uh#0C8mm~aXW0O`8B z02$Ekjsr{&Q57_XTvY8H?ng>ai!^wvoYkWafMRHQ4mqdv@*yjtcC;l*NIWdv&F$J7 zCv#SYzz{_lMcyn0rE!tz6<0A`xp3-mXhDHvrRZDDLsa;hwd39kC}!A1ful(yy^prT zI=As6EME_zwUQQn&*Q2h&Dagb0DJz@vcXLY)ApB`90lO29eEqKgY5p`eipnW%wCo9a$Z3d@ z{-FtW6Pdl$IYm9ny1P4GA^SXm+G>&x*eA817bR`n$Bl zSH!}mK&JohKUrK3gRLCuIe28YMh#cMba^dKolF3HIVS|)?1Y6+e^GuEGN#R&6R_T~ z>hOb)8K+e=EgTPYzUF-;f+L3&P{2fK7~H*DStW6&5x$djW8(YcGwjx7`<8cgabE%n zWq{wsYzF?I7kby^C5iMlotS5xm3csP`Oox3nXYI0K*5`vU?R~v9sJ}QHfwAXhONE7 zMU`CZt;TJsK?D>!$>YzL*a_0Ysi}Ux8xUpHfjOBSVFq^g2HWX$mK-wg36!GL76~U! zQ!9VQn`Y^4$5?*dsflT!`nmj9bWzYe_z~Efm=sT5_)KPMP)mNw3)<0vh+B0|KzDd& zZNi7@$+WZw0{-j$Kdez28mHvN)%%$eiuVKVuH(T@JJ^iEV1FV_bUq1rB41&mH~QsD z4z$|foO9FiGg)%}YhGQ7v@OBf+;=_(oVN~*#JZB-B*(^M=Cw)*s0xrXD%m?D-vK8mr^NFvKaeuN6SOnpyAA3o-eiLr z_*HT{gYDH1@p>lzSa@pE*Y}xbhwc5~vTYCAo}ONjdX;Q=KAJox<}@3#!Kmx*^ZR^- z&`C;?_NaIx%F1xlbYD77hn>}xl@Vv9TMJWB-7@9<`^>;N2d%4tSe9D*D>GQnPiKf~ zlB_!W&dth1o(hHTB%mWI=NnlK>o~f)lR$RdjQM_Q?u42syP>&+e}VopeXm3+>_GBdy7iOGy%uh`GHkX@tP+#$eX;sRf0T!HFc=T@5Are6M%i>v_D31s5A<=*> zv_bZ91(sYtKQSTfESTCPug25W*D~?|?J{|4{Pp;)fSs*&P>>UkXRsBW|09$Ku26Rm zjk9QXLk-kDdR}wCQkOBZ#$HbibyYI;?tZ-M*32SGl{N*XbalLQ&lq7W{BL$?9@XWUo3!3|~VO4naF4kHVI?JD{4UEKC<%}iM8 zOoQX(glMZ3M}N_kt`HL!2TZ&iI4$rj*vO7Zj>a|+0Kk2EBjpZSFRz?)&ebvnoKDesn4M1$W^>xm= zSR_$`yx7B{fXk40if+V2=_}nzk5rboF5Vk=;FSOE7wW0Ld6x)09SQ_RJyZy+5Yf;H zH73MFKRZ`{Nm?A2oEinQy`=_!HnRi5 zY<~ss6j)ZegmRoTVjC_CHdueRgIX;*K7Q;OUr)=l0@n7P5E@vAC!TU^($K~Pp4%V` zJ+t3crM0yE3KUPN-u((RZ$)RMTRNcu*gZYrv!dxbrw$$ujUkH$P&+!HCM2UEpH!bb z6npnItf|}f`PPp?M60fAW9zesLt(gdLzMOfC?_|y$owK&yhCzwwO zSbY**kAJQzri@D@3Ak{bl({%(jmBIDR~O&BTgQal=cu1IwJ<~X71$S)xE&_|p#aT; z^Dc{i3TRAtVh0+vwM~WJwi{h;IUwDdVCZ-hdNVsUrl?f=((dmu2NG?qfe^o2*v_?* z#)Q^(n`{K`ZKW-fj^XT1YP=|5OL>wcXvy-`ukcz?R@zZ&YxR?1nLZQg7 ze^#~l(%dh=NWk(5P)T{vsm)N5puzgj#GG<@9Y?YJ7*EN5AX?1{{k=OuLP0=a7O_Nx|w6lHA&ZZr=6kn6=d6`?5&>tZ;0HxqLw%T5IuM-qb_4UHMJvS?kj7Dbt5*YD5X)r!&SVqjcBZNdqa~4jfz{vyNJQkn5aVA zzYgs{T%R{lk{a_k{p@q>K)9a3g`JePy33}zt4?0MGLZ06?>;GsjTS5lJnxgR{JPc*)B z+-NjadNtT{7(b@`K_GICjl3T*3iaD;Vd|b6+MUQN1k4P`P+P=P5`I?Ot&2IFP2GFQ{dl1vsmIC;( z!<6~&|9Gae@%r3G;gYZurTL%l8jy=$Gj?}RfR6OHv7B9L-{_D3w%@2x7K^IX8LcB= z25~zToBw#re@nWi4g7E{!^IgF}vPJ27! zxkPwtK9#%Bo)WwB0)vX4I{DuVy@QeH6jtmZusSeah(|!84Ad!sR zzXN(C>|t@n7SH78O23^D|7^cag|UcJV?rk8nd+_&u`&oj@B7grxT?FES2VX^t0?F~ zVRpn{sbrrx9zpV8e&mV2IB;BUp@Zpd)?iO!l77rxBhF$iN}c_atzEq>OZtl#pn(>r zf(>%9mIXR8pT1s5L+mz0+-j>#W-#he=`&Rd%J#g4gE#rPncV zGG={gHJ@oAH+vlxLckd-37hY}B5QfE!uFkY_@;9;BHcxhnv-TWIo$X*!Giw4w|yG= zzATg{0%F}R;li$u?4;i_zCNk4>6rwUQ7F&;vzB*^Qt@f>-je@W{uCFJ@KHS*^|@rm z=K-3k%CF61rpuVMb;q<>mhayd!U#g=-+|-QmG$NEi#;`xC$7k#H-?f?5a!Md#1x#a zI+-gmG~J&7^(ku;wlGuW7I?nFH=>EVYNw7{31p>t$IGZ&)erck`!n7ua&lc=W1B-U z2`7nfoUGmsBv9&TCppgoQc<UyQ_$*$ql6|`uYnwg!QinOex36Y!v48@f?7oUVTf~kX_np}_nnq<$e1pfZXug~{E z<+ZvpN$q)G7Q-4Jd6W*IOp*%+jf@-Le_H~qFCt>~w--=W?!9-fIE&k1YU=8{_ncIE z^buR~#^3G~P`iLly%tZjp-<^{b0I{3TK@k1QY?iyf8~AITi>qwTYGuAfkM+}i4Q1& z49cBpm`+2jZ23@Nubft+2|eLX{BI>tTyeF0JD-h;{ReLI%zs<4&POMcZSD6pYDkgu z%qR~99VXXOw>Nn<8&p$ZXeP(m--=o?ll(r`e$CqzK*!abBhWEZ>-Ow+U6_nA51`I0 zzm69Uc@JEQvI=06M%1XDnl41kYd9m>cUD;Qq0m3NI$TrdT2b*gk%;^=kU1Npkr}68 z;l{v`ZtM79y>mr~lN&J*S^Ghy66vouEvzmM*7Etb*r8s!HLndZZD|W+0-{feXf`T! zt>Q>%5LxSZ&WZN1x100#=vdkoe@(RQ-#73dSEj;IRl&tkE%swmd^9;v>8qotYq>tR z9BM33c0sg(pH!aOc%9?mE!;f%^u7lbuv);fG-dnxTYlaHoI{WX-&por%u{=DKN^9) z;UEboX>{@)(F`iF(gCsu@0LX4dj`kLE!AD)=7$=S6WbfYL#~a#e|h8J<9vqZ*sN9tX!P213s*k|E%N#K3D|*$tois1(}u6s1j05C><3?Os;3Uh^sR($EB*X=aG*ISEDb*@qL11>^Kc>ni#s{jLjQv**Q#J?!QBig&sQck zcPUn@qJgP7fHPUE3sbeJv-N* znn+31HQ@GSO13s!cl=JpNbD)v9Vn70ZckW>B>LXkUs^Ek7!#wZQzMlB@?iUq^}a}B zrb2y<^#kdC_0D&RM6BpC>JpvzzI`Eof)Se7`HtcHJJwHkv8+@~TK{^i6q(u;`mLe9 zzPO+v=p4S#(7qGlxU-kPN1^|`aiH$U@{6}yb6e?FdoK9}v3|5lEpt;DX-jXD_4bx+ zS&_jE(j~~I1Q+<#7#>E1(OrT2>&y5V+tn$F$pd<|;@oLfU4nskSXo*g94dB#K)}Rhc2ue>%MVki z4HRqTRPzuQ80gBB{kEAqvOAm0*beolu2!)zCq!Ss`UHQjMV?@${%=irQ^LYIR;2RH z;>Vw|5gdk1Bx~8K(|GF@y$Y#*xMgql7Nv(_vC8)G71i^$l`ApY;46^tUpJca@>jnh zu5B*jPKoZ_^_O_`@WH*MEB|6dH%WoWT+uwGNSCA1!ilGe`10NOlCW+rFDc;!`Tksl z#E+D(ZtU%u@9c(0>onh!g`XmxI`-(DrI+Q)jl))O*(nG$2GABS6h}T-aUG@c&3X)n zieZfO>T>t;Q5u4-dG(~+>1s~h9HN@|ldci zLa(KsucS+R)Cv4}etRvuMH2qBxn>s<;}V7kCb0FxC%I|AGA@F_IBm&I<1J3y%Ne|cvR^5 zTvKlEuV~?Ds8QB66Yjbt?@u;laB!ZG>tt=(<_jRA{Xoe^L59(_?VLza3pJc zYNg%C-cA)EVXg-D)=UvuLr6A4N1*Yj;_a#xp>_GvTMlJk-w!m0@>;zq%Fsn$V`&9W zYhDd`C9=hE#o90N$9KhYBe8=6E3Umi$~ndDWz?rW_-8Bv&?65vAxG$)Su2YT(YyLg7q9huJkRG4*_M#7t^x$B5PP~`UxC;C)B|qYNyV(gEzsiOAN%_+ zZtzkAkDkS<7~3`?gQF|T_cSGc(P2T^jmv8sOvy|9GFLdfk0dv(B~R&6^;_~O!N2f* zBFjWqGvV@9d65|lZhq|%X7{J3zzZ|=@^{I^boG-$w$m8qf*J`=Fq_A*KG_$L0?a=g|8uDpfxuAlqecYtKFwWAMjL3{w$0SsOaU2*6$;$A=pN61$q_nfjhxQq6A^s z?8BvWtJgl`gB$R4KJr+pPk&EbFn@ipneLttxv75g%Phtmf{pUiBZKQ%WT5Kf0UMC5 zWC@fECs8Kin>~oC?9_Vn)gU>RY&ROM0dal3X{D;lvz%1Z7f~lM(eiM1BO;>r- z^?Qu84jj+~Kg^PD2p8&vX%!?JK~0%@+n|2XZ`Bxl{}jEpZgNprMoBVPmI#^7*xylF@)drJ~_PlA!f#HHyI5 z&*MDw4jcW)K?567@Ey%ZZ@xIb8qjUqWZD$QqL;iyj#~hc3HYBEztixx0_!y|yS>O6 z+wkCoeRfH6vt-8}@tG1~wBOyAuKNz$2{-lip98JkSRYPh1g(6iqm;bM{XyMY06&e28+kpFq} zd)GUa_P<%q7V;{_l{(5_i>1=9lSDl%lt=i19@2Mb3h5RyIe7B`x;n~FAViOLzkl#_ zT6TSgu*q1aUl&{2-(~Ina{{5hS z(Az4zk=Kqtle#3?x5dH8k7a4ki~C|2{VXy)w{u6yC~%5Zk!eW5))npk%1W)E$h!k6 zdNUxjF0a6mntt5XyZzYFCe|}6R#V}hv3>Z!=?+w+s;a8!)vH~-DuP~DH_K>rT{#uC zB-)iB()ck3XDJ3uzp068!l;qf!3ToB`Z#6RiJ!R>Y4R=vz-3qX1b9#pBSw5`;FRHo zS5Hwgb^R;Pk*87SEcJLti8U4uIx;hDtER7|o0@#Cm+%pgGz`^o7%`#J;Yc8RTm9L_ zvWV?e@-LC`*ORLvw)GVS)8)VQGeTTC@eHANU}^^4RNHhbOIxI(a9N#>Ip%_DoKwnO z@mCgo&5W_Q0c=Q29luk$g0@WWx|4GXveKs|cDKCFAae9LDPBX{)5ks!VGc+}G zBHl7VTpV0xRRG~dYn^{yYhPDG*nG_`u8UDWTzZWo^{_@^l(sOVKJ0m?H!giQnhDsO zKbVG2W8~VTE>lppNek9}&6PV1unoL}El60Ub#c7RjuQG5K(+YW0QzW{p zw&!{XA@)C{;_ji?BS{p1hA5oBajjA1?kN%aR$j0u8<>M_%DrbR(~8ZV$6n>a-?!0c zdFZwMX+^BPaZ^`t=>9`X?)qP-MSk&nj|^4_LSk+~7>rn={WMDY<*2s=25}n074O;L z+3{B-};*A{M*o3?cFFSV=u$`iA)8#}J)ydzViM!I_9r?77{5iaTuV z3xo(9;q> zjms1Bmvg8UB3;021mySUliuu%uD)NwfUDO(7=j%Y7^l@n)-c}Kyj5AMHdOpLTw+Zo zmgjetG@7mr&GS0D^jchQ-yCN=r$&cnEe*eG`Lf2}i9wH4975G>CSZF&(sAaaYTec) z6Q>I<@mb}|z)S(TV}>J7#CgwZbZ(S$=!(%jms$+roqOaFf-eP<;K%)b1I}<|aa_Nk zeZj~?_eG7@sis~lli}XT&`=y}_z%Jnm~MO0tVZ4o87V`+wq~@TzdT7Kr2r?4 zb3;hAXQJaC8kD}0-tpI5uzstOnGi8=5<#H&gS-6`zxLWsC=9MG=AS@r@8$Oq?w#Rd~xVInm;~lS; zBc(yf&4-}Z({UeN2@-D85WFahm8IPuL+;4KmGy|`NGL1 zAWnI)@JV6{{3M!K?J-~CV#GVdD(vQvT4-)`)CaDYW2ZH_j1TY}Xg~nZ*Htb72oJK* zwBT$WJlQY9ftwJ2>TmbPS*KzqM%|mj_+{{oJ;oti?fGeL=Gi=^rq$-g#_N!f^;k<* zB<6)DeQw)Wahx*z{HR1bC3S$SqO?3{Ti>YnP!3ZTnwNi7X=WGz+=wY}Zu8AOY4EzS^NqtG6N(Gd=&h0kO4q)YF-C z-Jh)i^EWhq>EnLTTja(z)vF0oZB(id1E4DRM+jh&>HjAtM@9XuC6w2#W}lr34Z6gtjx=+`&^(u zxqKd)-*7$$zDpnP7=0z*re4i^i-^NB1Kp%<{mRNA_y5IO8?(rhn8y5swfHeBt9Xxn zR8M~*);`Mim6@H5h0no-r8}o0R8ctne$yl0UbcM8@t0y(qPAPq2iBo~h~4k14Z|K) z?M&2BolLnL5L-JZxH2eHFp4~k_H!1h=^Flto?pH|<8UK!%A8xtgjI85cRpa|hz^yJ7$^#X&21Q5R1%MJT3jT^)VezMK;INdMg6 z(2&1?wT>eds4ueCU-z7xgodi(eRXj(*Farkk4nwQnX31BGHyUpvIxJ-WHd4M45WM= zuy`tFgNDbOuYgpva=*XQR{vDDV~;5s5uQf;{&(f1GPxG0I;`8ASZk^rHGk^)48IKn zM1$BdE9geFTpA?3`6%0eV30JV;v>nYFPf5n$mT9v+uTzhTbRY z3S7Koz#0pv#OW+2m0tG!*v|tV-80i!;9sF!V^s4q9qcA>vWMXyccu2X2(c;^#pBm^ z7UsU^1$LyMshp&4Lfm$I8^f8My}fj@=b0T(@R-}e^9_-Xk&o(NUc`=nnr$A!vNIB? zbO{jnEcNW^?Gu`%t;0f9Lsk3msGDRmPbujBO64kk9qJtImpLQ*qi+6D2;N|xJ-!W* zpaX3d_5b(qf%OcMze7EH6_Gt-X&B777~!P_3drEVKoVEoMrUj`0udkK>9%1#mXYad z_N3dl1QG(|NjO3g8cA60`cIy9DGGt(KCCUO-J%<4; zOPrGFOKz|NcPRW2ao1PGZSy-TWD`;}UHQQ|@eZNsV$-u(FJWn_mR1uvP|;2{i^$4r zkN3?Sbx)=+O>Md)usKr634u}6>on$Yh#cbULQd_b(1B$PcHFinv_-TU^``6tYv zyFnKjx(C^U{LA9*EouLy2({gxpvcb|06R^kF_`1Coo}0H6Pyw$+jr`HB2oF3F*Mx2 zqN6j}ZQ(`G@OuR2)qwMeMw&yr(T-1TsLKiBh{)@{50L+In9D-kEXsVVm&YBlRw z<{>Y>!Was1GwRz*YH?3BHV8Su0Aj6{h`4WIIm8!ZTE9@AoAsT!F1(^3L*-!O-Jt6BNaQSC1e<2(bU-)j;LsXAwcSNdkB!Aef@j?4?cljlGF7Y=e%j zRh|X?>qQ)qtFgH(luHPr+&jZh;}6l=J|P!hjV5KLrOdxs>Ecjw7#3eLjjn}4$ICON z3C^qx#O7CO)yTHXpewXwXdwpLb7%=>qO z$GX(Y(wXAjB=8lXNiD8ou_Bd>d%a#qX3ZH>i+BZB!I>m%&{K@KQhRWW!G2W#Sp`u7x(f*S`dH)*P zvKCP+hLrdX0CDn0^MnYHh=(}ypH8RGp5T$c&o>N)Wb5fM{!q2>$lidojuhp7_KzCc z#adIA=)|A*3_l9|>zQn)iyFTo^bT$9@mGya0Epy2+@(ooj^EG&=r{3@L1o`qkHNO! zQtMhn(E*SC_l%C#JR0qrX`7e`a50VowTXV!YwK5L@oh?PS1nLX^!)9E-8$Mi9+zig z?wr{H6=ZCrF&D7(9`PUX+2FVepYdvG`3;h~^@rBgZ_o5FN8L9@wJt6@fePKn!9leW zrJ>ee`l%^82v;lsVQg@A(d0}u&0J7h1F!SZ$E!LkqIs&zeE|}2n>SoED!(|R)huq)l;Y5b8YSC}1)e=I zTbSYFcR(deO*y|_%C|=RxKIts2V$)YvQA9kzMUZwpR4ga=yse<9xp`?v^vZee;Cn< zf6VGA$e0IY{V%h$-k*3J0rNmkuIE*dKKqt1QvgB;uup_t}Vd zocay88sm?~*hx&h@p9~KZ6glT3|#+k-!d!z!V&w}k{6G0F=spGB9Du&Rqa3Gg@bc5 zdW}o3qECoQL7|95528t}j}Op07a?{_HocGNZN?b#Uf8#-=*GFx zQB*w%$Q}c|=;dHhZbe+!?qT2bPWY|5wDjw-Ca;UVzPJ0kTm5l@GB>MW8|rD*)80Z+ z1^xqv)jWZiFRFjm>-)@8R3XaaOG7R=nque9+Fg3jku6AW#a^4Qy@iEOvKz-Kyk?^b zO7CvdE}jaU3sBiDh$xm7g{^-(OidYlIp&+p=fK5BE;`!q{3ebAygAowzCcZB^yX$o z!V9*di|-+PP7rsM&X!?t+nHdl*(q?`D9J%Q z=o?I7kNOkkOGL9Hp{HW=-va$1Aj&PsDo~>-&%SZQD|VQNZ{>VM8Jn5wRqK~m2)l!FMj{&ES{*yT&o(m_zQ6Q3+Z)1kD!bV zh)I+;UQ%Kr9vzRGTkl{mF?9d_U*&xfJzf77B7ohly%={$8&7 zKki+r%yKL_DVc7v&v?6I4-LB*GH z%j1snjlVyW&72TO@(iflss&QF$dAw+=ieaB5LP`?)y}cDG{-PzAk1}E?fo=#vjei< zaKrvz!Dh2V288Ry9m_~`bl_Nh9B!#60lr9-53U!QhJ%>Ua(t=8V~dB*0_Gk-h{<0% z3D|qG-{=%1VaifAWVm!1u*YQWF{k+GRO(;JneRhDA<#~_{@@ZCk&S({Eiy!fZH{)>4AycP$~xv5_FHf?Asy zQM9B82LFs%Ms%K*SgpOHe|%S0KLiRh-9tHk>J$%Te*l-mT|faAbLStWD7 z!}iT)))}=`$+5bg<`%@CcTL)}=KtaAt)rq0yY^9$P*4O(DQN~!Lb^dZgrNj!krJd+ z1O`DuO1fj{4r%Fb7`jVJLb{uCkMH-M-?z>=>-;w?)-&@w`@ZiT*L6L6r?B$=a+Z6W zaJ8>8lnrh2LS_dMI;XAux(BRNojX^uNwd!M=AS-+UXm1o@B(eH;2PH7!JIJb`Rw`W z0(v^7bDHKUQv&PFj~FE3O4n4}Mc5NKb1PokqUMd<%GWA*6_Q$C6GQ@?ajQn3=({xh>b z|A}WWSWzHZ?-&hFpcf_2@diyGX7Uy_=}L`r!ndm!D`>j%?mTNQAws7A?6rDGF`Uu- zC|^INKCYTxz;L`XZa@VSEbwbgxv+3x$3s6tVqS%JKKmIou|O!gu-lEv?ukNB&%FP4t~He)1(g-VzX zEM!QGZ(Ih94Az}3n$G2ZUr5ACBCFbw<99mI*yN0OM!!A^jY_J10TcalJCWV}`S;^c zxi?L^-BWqdhX3Vue?)n+Z=SuWPC+1-;l8@GG{X>mQaz7K7%$@V+?p(kPURy%v@p56DAOBs1vs z|Ng+81>(9xNlXjHshyN{Ox9G+a;g%p;3<3N-8@ezem~J;Kp&t+%+5T_ zQ=ciy;WTQ~2WR2)aeAXyT6lo@$Uz?+0;FWkspUk)#$dNcE@gB|5F_vdqpN6d8ILQg zD$NSr%vo=I^k|-D!-r)t-^w=O4UJ(#4jWL;rClx zR(EfzHF%td=q+`~bKrmoRxZe~33KN0*HajQR<&>Y>jMgKJF;;NJ5h*DkKzfo?gMNS z%iGcIOH4D=FKi3_-iNeW@6#~AUgvu>sg73#CZSD)1=464AeO~I{807GTbxMxw$?n znTP##TpY;B!vTSKv7@6L;Qw@P|l4#V*ehNLTNC^ppVWBg?k5Q^1;LTSD5$k4n5jMz-ZQ^bYYCtY4DeR$f!5 z+|%KV-^pl_kG?h6UFLjcw0?A99q4TeU$t=*d+&m{7_)3Ax;IjE@?sDZP%uuZ?sIa~ zGUF3OeNjm?cs%xC;Nt;*lf-retSe=>R?jXTj@>)2XT!>Mi>_Ck7koV6s$pQGR0b=o^O#b{V(J$fO>ijB*|`P z6t<_@azNwYdpH@p*L`!}o8@H@;a}BXKXz^b8#a!IFt7_2r+%FI)OY`rhB#(Od5o&K z+eQ%a{SHG_OdDc^y{e?Rw9GYD>KwD^{7tjlY(bv{(^K?;+pH^TFvh^0ZDWy|CfBl%wKgOI=pd;ZYIP4W@O z=9a?(POA;exT(c_x}&ELuDymz5*>fDU`6xyjU!rjjK&5H#|Ik+s+|_sqGtT_uat1O zQ;4WbZ82ImI^>W`Ks=8PD$(<4YIE6i>PLMA?o2T!b|kr3Su8ZvaSnH&8)&DS8sdBR z<`OqXYm;rcs-)80*Z0V9N)SHErrbgj>!>Y>$of=$e?4M+3CTp`B=t>7&E=izy+r6; zg#z%NVFDV(AwFIXmBLvd8mk8xb5;H>zEn6Mw75oMgkc7Zo~Rn9=cqSQ5dE9gyX$M+ z>wSuIq{Jq=a7P)CAGb|Fo<*?WhFXyox=>y%VJ>}>nQ~1Vrr$RW!qcr<7^3HIrYY_+ z&w6TRmk3*QE%n2tr3Uxo(0Z>SGFojO*)uvDPHNtq=F_c+pLLJOV|l~AY)J%g=q0I( zGlWIHMjhndWsO0#@O??1aPaUTzPe;z>~oH0IWjvMZl(JFV`TM3^Va*K8Jm_FMUOU8 zBafc6&xY^Th~e<_yP8Ssc{V;J)umc!`p^n)gPHM+%#2f-m1z$S!L1J zHzM zzy2K?Tkavu{c80(m*|^MSZRca>Rc*Xx)vtA*vR8i60Sr;Y$1Y46s*r4k?z<_oG;m> zy`B!YJ>3lrYxW(A5CY-kJN&;9{@-1+_q7+mkp%%69;m-8_8eD zzp!D4249vgF}ZL*hcv=r92VP|3N_=JN0i?`_J*%Fn;X3X;1k5W^BNt3_Y z%Ynzm#k*|J4df}fs1zm}L4E_(34Rc6VWos%p1Q^Rk96tq_jmzgLqoEX;-9~6Y;2^% zz;Y)%O$vRqF!!^RBrhh4(1Hgo*(*|cUca^Or#~$}TbLJ~h#S>XW&JfUvdvhgY5h^p zEn}E}wSp19*~j`N+bYP(+df03SjH5v3EKxBVrl^lhlu0m_r(j#o!P=ii_r!*`Kfu5}QZy{6ePCWfqkd6`)Wuamf}cK_99o@T32(1(u!^ntY){!YK| zCb0Kx6bkYqP&H2c`SLNg1)Tpl9mq7cn;xy57_(L+XN5}b>lWuCsfN+!p}<1^#bx8bKCYNe%1 zzbtVQbq*H)u;hc`rPiA1hCJb-v~&Q~EZJIn*2EOno|ROeUK_X~fBS90;{l)3rX8TP zYA@v`lCN$axbg`&2`4*gR$eQ0*tE&~s4llD-x~roUSwd-UGd|f5nlGkS~Yp)jSAj)JGd=NMsIJ1b^Zvsi~Ne}lg$|XE1)(?Vn)$JGDID7tpXo4 zWC41azjigsVYRL8`h(mvBU6dx25lKDj)(X|=t5#P^Cp3)JFm@www~TR(4F=DTBWUp zMT8}oFJ|vdVZILT;K^Yntk|1!ZT@Wt{7h~Zobehouvbv{q<7BxHZK$K>6M8tpdV+y zF76i)(m?SUe1cQ^_VQ)PRx~5V8Ry&)ZI=>35UwS3gem?_$zn4#D3c{K$D=o~ZOIsD z3}@oWs!oekM1k`ic=%V4s@HL81r`K|(cH`lZqCOM!J!E%t`Q zP~D^8WD&T=Mn>c0=qSM}`AXj_&-H*F zfQQ`{{vpr$E;t?mD6{r%z55kDS;WTtwiAQvTQ=%PVm1iZvvlRuMJHM&&@@sNdRDsgntc;2AX%P z`8gR6%BO43?PPyV0=cs@fA&o3bvo}=IvNbzu$QSHI+O7K$SSL_2Qf0oDXXii6QIT^ z_sF%z5gt$L>G9SS>|Tj(yP5rQJujWt;}%}|9(d-q^*ITv8cZn+UWXO3yH3!2vqIcM4Kfz36ToPe4G9`2iX##F{9_e%sDm9mVC%h7IzrP==VJ0a0ig*)kVB&?2_ENlel=Q44@MsYzP)XSL zq-Vs~M5T6Bibtt2QXiwj@)h^^i-&tIXVM3~#E=Gjw&EcFhyDcrrVX-ZTblugSn^X@ zbO0<;rokiG*b3ka{quFoy)~-lH*~xEV7pCB_BsKFDNjmo$oj2G+L+rxUn+}SJVVwSaajyc>U}nx6{N2M1yGT zd;4I;rTHniK|k_BzZ}o06MJdT999W~fHVB8n91w^rHpk|!agPY4;5bedVgueX~Yr3KhDc_j%NP;q*=v2uYv z{Pp&l{fzVnk*MhO??>DFlN`9ezpIUtG%&E|>G^z2IT-<5;~2u*0wGRj%I1 z$PjOli+U!iNG=0Tj(c|M1kb|UYNn^*bzaR)Lr@~|R1(Lhry1Ydq0VbW;*GwQR;Wu; zOPywW$H#PL9;-yUrUcag+d{XcWDVZBwC(~lgeo%;`Qe4(B8Pcw=V-82GYr`aclqdo z{eUN70ueg!au!<9ip{rQ^^hd%*k5)qtv_=lLo7`>_c;}c7aYw``t|TeJ4xo0`*1I| za!cE6s2;dQ>y*YJ<7LMut27E%he1-8eqU&Ak}~?$lx4v{(AKx_N5|XNoh2Uh6y}7A zjs+;n8m~s42N>Lmncra2eOvD%?SEOAitsDCA_3NmNGO$&kZ7B!(o|u>uW?M~{YZu< z5*!X)hP)mzBOoV|;CMHEIkV7$x%E=F@dwgCZa8q_O|oY7b^D^15m|9dE6t`&U&W+F z0^q?3?5Kw~_c0t&+G!Lx7&u|Qy3!(t_^S|uOI|#1R+=uK-*4VC3}yu5bHsZH%JMk` zYItaBv^PD^z|M4`>J#{=)qeE97X-4m*`0Noayd8>xjp=`#I>d-ovLPzl`UB&E4EtddfvDHyrmdm* zWff`9Prp$8DmroRC(0Z7{6T-X zdXOiAtv0;$D7Ag?xG?#F65*m{x&w91b>`*;oY#`$E|1#`cj!njlF+m`)8(L*d>5FCh zM}xeS-3$IKF>d4nvwa(|3S|Sd!8CZH0c6pPv2Y)$(60hum@3jP?Ygy9KCRH=IYL3% zb+eW-E~L%-4H9T#;lbp*QmxRr`ezq(un$I)3Qt5`&x2xZJTXN{L_<_0|3Lh?xqTgB z97ebHUXF{n|7?cl*SiMc=;UBz3=Utsxz4Oy0V>YTuPrS`5X6kzs{8FU*;S}s62GT! zs6lht>YLLZp)$Hy_*}l{D~ndgJ1>b5o;_jrT7nc)?LYc=D6hlY@B(cX)~{oRFXaCA zHQ}Vx&Uh-@>WVKH&jD$o_3IvQlRPkN5oFoa7fdl-(5>e;Sc{jpsQ%4$b{k`r8D=GB z+d>3fTo%f<=K;%gNidrKv1l|4l@PEkh=mCgbC$q|x0QW|_P)TR0e8(* z=D~7vO_2$unxxyD#0uYgt~0A6jTQS=Ngm0S&Zf1hexGwXk(_=o$N_w~@nL_*`_X~X z>ZE#4v!Squx%ec4fyiB2#!YsR!4UCS9tYDd?5B6ICDOnk^6Ba6wRILx@*mzNe>cp? z{KQT}0_?mz>G@NvY!MP;{8Rh7JgAO$EWYj|3(_Z*9V-3Z+GsDppy0cWi&RDdvBLw{RdLScBi!Hd~cx{Q*GTznEaV^1-&5Up?_#fd!vZl zn>EPLss0fTqBx~^ccBvJ&dJ7U;9E7qI_1d^R^A#V_3VB8pYd+j5v2iIpO0-jUp2`L z>ib`Ny*6|Tt_*tBWN1Ws#^uynP8^vD9*Ne%R3>p$jR?NC#>K|;*OKj@Mv1wl%%-iq-m z9^SpY0YiD6NhR>2T3JU1sPgL1P4SV>U$q_1@~!k`f%_Yd7lNpC9#<$xXY?kiRJpk_ zG@CQIM%C*5M>HoT-TF3UkV8d}^$};;#4V2OKeamuD;_jVd5iQ9nzDTN+$a^z@;_em zjLqR~{WN?S04LBd27z^AWCSti6lbharC~g`${*~GCo0#|?dSf9%uVT#N@1evRM||^ znwqvL@uH_RU1$ID;vDypHEMLa1WqCRKhvYSzaCFFm?ZaJnaDXPX{& z&TscMD!ia<3mUEqRWK(!3i7)~^A$f4IcBnO10unQ5U`3nQ~DDgS}iR zHJ$G%Ekl4WP0)HLUf`7Iz-P5!b^98`nC9l(pFXZVYyrRy&JQaq#>TmO^WnBLLLN0( zrkxXwE~5^n$ZK&!uTIGx&JXDRj8Md+Q>i)+iLRvR=XVRHgW2!hdR90&{$|qsHQc?q z9+F_DY+-KFCi1>Y@B*_x;#)@0>cLvd^6?RH*{Zn4T`)5cSa#MHKaIM)4o~#Ac{}^5 zYGA91w?%?}{it96S0E5B!0hij+@|f537Hc4Z(i1Fqh>KM{4pz5FISKQ9C^y~M!7~Z@;4?tQS_=$hc_hxw&QbrK3N|vmPUt6V5)t&i{>Hxpg zxTYKJ`x&P*#RngS{in+u*oumGC=z^_r~z=@64=%Xub7^M#1~#x2Q7t_Q5WEx#IBuB zEwJlY0zh}-@G|t;M?s{BA7?rSx5*Xu!pD3Lw^%%p)CZ9k2eU)p`53ip8NM}KV|*bY zCCMo$=yDYYJ66nFvxDwI^IsHwp@9G;Rn zyheO~6Izdm^9b`Grvff(REaNdeBS|C|a0)qcB)}8(>b(jz07dBW38iECsq19=pVKqB z7n49&lx@7d^mvi+I&*ipM8z(H+qX41`9aV6^Ix0OOx}{e-~zTF75{Ew z^=a?-hI?b-?c&p8|EOTga9PjW5p_heA^~h<=D_ZH%oQ+tFGj0goytVbS=${Q@2qUO z9x!x$OWnu+EWNt`0|l83BFf2w2zS$F){UHI?Lh6%MCsSyxL)Xc-J_W7kAF81O4 z94-m^*yMPoi+uq{jPM<;6#9PB|_7-m5{Ur}6mKJ>?@m+z030NCm!7Z0Yn<@zFPCIiLf7vj*3D#}XPYPDy%L0U6m zGmqmT2c^xUnU2~i{jg|8$8dyi#tZdY?cSiLOPuycYy}*joM4|()=hC!USR%r6?`u* zrPd*Lf&^I%9F+nbm4T!8ec@sR?!|=*WBsjtT}?-xs|7O)l3k&dl@7mb8@w9)Bx7W+ zC5hOGqbIaxPY+Kh-)UT|dh&Qa7j;VU%Vy`My%PCk<@ZwMJYd@$5%!%Am3HOW>VZJp zkwi}M^o*d7zZ{UIQKzyXVHRIWp5rDt+OeN50CqbCZ;s5RLCts zKJ>7rz`NcgF%ej>=_fDLXlCu(M;lRUf|P<;$G~AGb00s~K;x*rV_G?c-==S`Yi;2cDZlNl;)Z&M5!*icQA^IJ1J zZmn)3kjXKvQP0V{eOx&nko{mOc`N9gt-1`zz`Vifa7W->l&yz2dhX578R3W&VjzzU z9cC+se`eGHbXe%T=T2`ZQWrm26%1Z$D&_~FT`S+?{BP@;xfgXf=1R6WDLMHoE5yi1 zpiHKlYr8s(=22G3q)>9@`?b{6pG!sz63@u+cr3RwwW8iDgUq39?DBBWiXVMxn3l!} zzgb&-oADtY@O&0@a4q>INSXTZ;Yxb+CMt%1Cq13~_2W>ASEh#tkJbo8H$e(+rgZDO zabEg+Yf7%%$S?HK;{e%(xVQ8$2@7#>?b!ZmDEDUF{cp5>A_&7wjo;lee`a9S`aybJbf`{TXA2L>C+BmU7Nl1tY zn~s|0PP0=GW69UX{q6B#dz&lJB?w3;Gu^E2Kf92GjSLySr{cHxJRd_IF;FypL7I>t z-I=Y285h?NjVbQ=3I;gt4ZI^C=MEudGkl$7Mg{6C@ai*{Rt0mi@zKxYFE4G)-4F-G z7u`^hN4l`47+w)S-f4RHZUgZgU3be5rUIhIi3wq}E=i>JfT&c~p)X_v?c`IsszvL> zg!63y$g#g?wP$EwXIE_5nXhH^PQV#gC1W&{ zcj5g6|E72z>G6z-wg)8IiIq5>HTpMbmJ8;Tv#?6%} zv}*7$yd64Hy$;+4=cB)%Hjl9Mlfw2_lAv9g0)^=E))Ht&28~xJt6^(;*7yyeDG#9f zI|-r4Fngd5y^;2`h8=Dmo!;z6dhT1K?Ma-wt1w2r8D<&}+{dL?QK3rxrC*x^8JV0I zo_AXn>Vc98KKNO~VMSIK)eeNd0O*cK>5fJab|HO#tGbGso3_mOM=jf{@p8eDk>PLv(9~=l9Bi+X z{jTnV)+#=H)5yEDBAuq3yoCXynLWpk*Cs5hzovv;xezFJL&M;?y{0aQ__8?)%u<(^ zRi_Pq;nxVp+Ph^BUGem)Dy5k}4cj}Wz(>beE?o?_Iv5u%;<9lh9Pge7VV{7OoX=GL|S#a`ujRb<{SSL&pG*EZ{zsopXtKA$!N9y z?%CdgACoWt%qx zXH+=%g=m0M(T_L90dg7iB4>M!uO5O%KTmWur>AMJx2I+VSBdBAM~~&-_Eay5IXPhy zlKQL?{Rv-P|Fm-Be@OoNz|B!s46Q7e;?9 zE5ILMSh8w0l!8!@Z)rWqq^zd)mj{_hymB>)@k&#<&Xvi6L7&yB-E6cm9+jbY$Ito{wIDJ;ucgora-F;n)vo>NG+j@R!-ra6$yl;k|SyE{HP(a3vE<@o$$bmZW`bb#~xzChg< zqQ%vzX)ul5SA1A1&}HgkJ2e1`9>|S&7^K?Uq!ytl5=k{_czMkzkagew{0&Kzu3(h= zrHp(I)_9bTRxupQRrbIqw7{LY&jB7g>(1c6PR@M5z&O7N5%?ya)~It61kY6OqMID~ zd$bOD#f10G@a4Dta@w&GXXm5C)18w1OvuQCa%L{Z^1R~W-Knm(zC762AuUke!A9l^ z^A8L)?d=OKa%((pf_e7a6FjHy@o&}B6cs+{1Srnx>*tqm{$9P$Qx^i4ecE1ESU)P^ zCyf&lXwU$=s%q$p;5F@_r^E2?FgB&IV3;dWTn9GQ5Q^h6O7nMVA~}jNF{N0jzv>3+ z@GBgwcpkGJ&~Sao5m`1|)#Gc5)2`f?pouLWn5#Pbto>)f=U^1zL(pl-`Ugn}DBZ)X zgK=;S7hovAcRDFtL4+REt9RZH`(BD~mcmwGDVTr;4qn&&zTn!Vl#3z!@&mjHA11Q4IjSHU*=A1>spA#O$$XarOMl%PdmlhR z)t4`?>9PcvYXm-8IlW`>=g#tMSI)Io1E=)hj+K*{$!0#u!*RebnM4pruYO$j?7Uio z^-FUkT$WYu%Ryt=iPJ*Q3#P=fN$Y+A_0K!{N1;(<$s5;_*Nc6@Ft#H1dZRnJeNK-n zFNZ8Akk(sy$kh!5BB0Ht4p;v9RlEQVFo>-o?%x%32K$(PO&Wr9eDcKto`Z7ydY(tq zly^(wxQ?`z!}GswdHe04%HGH?z#Rxh&A>bn(O>jp7HQnkBOf`>Qx_r~CQ8Gzt!istADSDvu13HInP# z!+)M|<24aHF38H~LyVpmCvN25L_CTEIGV3?dwd&F2fpw2J|!DmKt5QrCLnrNc}>LO z4M{AgCFMDkc5q4gO}IUu-rJ9k_AEn!S+lF=xL_gIRjEY-9W&-B4J^{H{**0Ab zGe=gSS?K*$NH0>J+CIX}o*^YA;?s<-sTe#-@fuN_9l{0Mc~yIXG!=}e+sci9$oUF|;^ z$?pmoqYB3X>BF^-`5Nta0T&8B^acIedDZF51beeUUD$oA7dkND38p=_Y0l$amU}A$ zWlo^5obzUXI5;qx8aH%z+t~Y@SISR);AaV*U-_xWWBZ`LwE#%nXs_v>`Ww#?dqKbE zEcJAljezoeKQepW6C5TDW%mcya~}Ks(*>0-qz2s8o>b%OZBS7C*jFwa0>84)x<<~z z%4CB+$aEq~DLOnd!o$PO`$|m_G-pCd6i)ma|NMz;$s=dPO z>>tR$qaul!I&~>?@co@N`mHG;M=N5LA2aaBcd*wP&EnPLIqx__VmY$5HQX=p7!S!e z`IDZg39WPLBdX*d`&)&iNbJRyGnh%#!mq6k;asOe82}}d2|SFXR(L_9nvXid9KEX| zwg$o7ELn`ef6n=#w@~VD_3rFXr@Q`(7r@1@ztmQ{`OU)gC+jFO+sspZ>N(z1L6eE) ziv9*Nm(>BC2yy~aZj07q2a}UboX*;CWjHrC#v*NOyLG$P1~s`}>$|T%&0x*Q$rJTgy9M z$7OxuzriNi<)G<6)1Vd=}#p~-xob~+0c1rKBB&42_@j2Pt5 z^cSE;+9wFK;R=Cs5c|Oan{pl>5spm>YOzAuY1OlHUix#nPhDLe7agUvogw6cCMSLr z`@tI7))YJ+bl)BC17IlP`r7?ka@biI1_#r;_aK?1F+E zaZze7cdxxS+Ou|894&0H&>C+aWte4(!9#Z_v%?P_hWL+eFszC|Y^2D z$lK~rgLr>o0P14UKESe%|A}Ypw9m6U>rv1980b3FQxrn3(UEvV7jm#+>`$}$UM)|f zi$r_AqdWss-PS>p(Q*eWX5Q*1&F^rr8_@A4=<#EXY^x&AL$~#*7di%A^mL@pNNpB8 zeDD>AE_$NtK0wTPDVtE(`HR>@do5dqK$gi>{u2wJfi*|Itx#=2k!;J}kx_ib#PW*M zCAMVPgowMK(Sp66@bKa48!egnPN-jK3R*@1UXzNPfTs3?J@+@)@4#YJtPg3iSnUAb z1su}6p~9G$)6`UULeiIf2G%B4{{IeIJ0}#mQ2c}jQ)3d7YVU_ zgPOeeym$UDW^Uf#9N@cM6qXP%!PNq1G;QZM)?pwgD8X9yI>Lly$7cSOAxu~^D*7}4C7;Q8?0;ujaQZa2J-hb?5K)V{ zjn84K{Yr+Z{{RWWqtSytG$l%796d8PxS>*HX|~*Y1#THdpBC^08BE zftN;_m804sEp^Ri({%4+rPbgo#BbL14Od1d=aWK@?o1*&*!^8CtywS=T5;D(u{=^k z!u+GLP+|`t4jrzp0L2L)W>fr}f$Q`{WecNqWz_{Fbq?I$9yxh(+D3mgvr-~pJ5z!F znQ<11hjeG`0(KY`q@pHIAo`588fG7jKNx@b^6O_55(-uvymLI-_eyW`o#eZj3s<|B zrQdinjbz?nhc%w4DnKCc)K7h}f-w|_^6xsX5+9cD7Ru$9bI=FdT5dy_uVRPrtc9S( zur0MUN=t4V(3bH+oN}ZLR}Q2;se&GE#R;{w@iitO@JTZTz{!PN(Je_6<4O~|RTa8q zSga^=%LVryBPpYp;sKxQ1tr$ZudkXmvihqItKXg zqN0pPR?~03wL>|aDPpLI-5x~1!A_&f^%sD!Ef^t*;+`E19l-}_F%z8>HFTmBWP4B^z-A98pZn*x%tQD>>m$9QA(c;`w|z*%?HFeo)Xlrl-}fCR6O?`UX1K z1u3$gi^CuOv9o&hM3%L`T%&m%!}`B`zIvU!WE58l$b@4`g2xwaexbA^LYf*jrq-BF zBh{SLfQ0}7BqJ@&(8|cbu_(s4YVj-8M?o%*6eK-K{j@ZUQu2o{a8I)*Ti8xSMKjIF z#rKe518>^4s_%)y0*rYCV2`JKa{9X=2a%OIhSgR#&sXlD`l5?w(ntYq;XlJI+{JuQBl2^d%m zgahOKALKYzdh-oPPW1!igqoE)-1z5Z%iylQ z2R*rEt0U5mmI#4#CIZ0DJr{HdGIl;JlzKnfG8~Vz$~W&;x+Dl!phsN)T?418DK{UV zclaIp1!nNFvqaa$$Yq~PN7QVVNq{I4!nw-Q8CaM93rwiSYE5+X2l9S(;pXlud|#U< z-0T-80HeT>sCUmP%B|Q{8ui@x4+(9c`|KWgEj(k}bjcFA8?=#@qMy%r<#hT%b)&-M z>?x*bsq$AOi$9Dc91|H#iLeeLfB8sak{wV=*7`kD{e1i|cV+ZHY6yT9sKQ!Hx#eQ0 zinqsSwFF|Ekc@wP6P;8qG>O`oA)bQYIZ&)D#*a}jk=0G69Hvm)# zTzRhN&VY9VF?3hIQ6gjc=JLUeAfF;o_cbC2mS3+!SSTpjbZz3;O_V4#L%qBtBwCFq zlIJlnu;*P0e*y9)$@CwX^&grjcXx8K4NCO^Px)-GP;n8RP{`x5G)VTkeR@DaY`)21 zfAuY3orHyNKo*S@#BdmaH{Mirzb!WN3^4LRyn8wd(;b)p zqn@d^i>lQke-7>ua>lc;&o` zrilXw&_&YO%h3x=N3_u9;b|6EBcghnp&;X7*&`hDcsI~!CmW&F>dNsr84d#1j~|q? z1=S9S;YVe&vCV@oTsi_q*9B`ngMb`XVd~ckO)#kU*KD00$FFaAyU6PH1CX}X3m)zL zt;~kk6@rQ-Q$_#Kwf}9$2o3oU{U}~(R)sHAjLomdYLpFI$6S$THe9b{Wv$Q7I1o_5 zo~jB8v!IhlZ!!<^IBoZ`5XcUOHfS7tH=gM2e7*$|CDpOi@@%Z*unWKMDdVA_x|7lo+EQJuX}>Pjwa3CZ^;#r?Hs; z^C!>xhbVw`@hPWiUH*=u?G*d@b3oX%@{fa9>KsFFLu6szqFHyaDJbpY3Mu($VbR$h zYRD`3kCgex6{po2fb+~$0859A@N#h#6W#Uyh)YPhGv6DM(S%0nG(S~{IF~z3E1wal z#hunGf%UTbKC@bgAlPgTE!}pr1boryQc27N&ydBWms-;B2RYXlQ8TCZ#yCD8VTzvU z+3z+X>I~01-f=BMe|EjcRt%tIOQ!BX0*2?CNw$pK5CHuJm>ENcM}%4gUOlw=Gqa$&a1I(cs2acjbvGr2T+uP1b1mn&UAxwl z)JMDtsbf9UAv{9iI=oh5e~(wX*e<&# zTaP#FAMZjuydIGpNiRe8CkEuS0r;<&GO%f;v0%;!cs1YHKt1_oh*`15?3BR9))rxm zdYM9te{+~Dd!4nylQt+40{I^XGXLu2WFKGFfv5xs6%vyx67sYk-3^-ep`mj&sbG1;k!}K_hA8f)8XPj2-yJc8jw+< z-lje~#V_`8kkLD*%J45rT8xHet53oM8AsSh4jE+GcPoD^Q?*ddv=iOd};-%=YZ17SK-;(>hEVI)elXDE^)-h?!~PfDQpO zmxn76+=*!Sxrup8KyrTjY2kl62kS}A4k(p2IXO8B;bD-qvvhkIkWbvd59TlSk{Q_h z0hz`9P179*BYcPN18nown-)hvj!Bix`Kp{x%RRQ7+854M?HO18F{HM(6Eth0>ix_0 zsO1)MlOsv<4Fonsq_`ZAAS7pNDj{||8BG0^^!{#{9R;0bbV9$q_gue?OoFs20}X?d zjy=^+P__!4&y8EQ_}V)>dI1y{2`R6hh5=qZzrzMp^3*hlet|hcxk^X(xVn$nXjcUj zR_j6~-&&zmJAxX885v{*cs={&gL=(+_0DR7w|fr;NPYI)ufu5 zL+^Hnr8@ntKJ2~&eb~Yab&Zoa2W=|;x-a%AqadXLBHo%`ZW56f3Tm=Eu{oB0ujCv3 zc<)ZQ=?)?RQ!374#rdcJzr#hAr@{TkM4<*rgWWf<_{bp;ZUhNO`cZMv5oxH~=YaeF z;Xeq0l7p96Z0hg2=;yaH&fot$fwRv46z1i#e0RMeS4}n}XGi1<@3#E$jC1G4Nd-Ema`s=SI68NK^^pz z@J%v4lLSq~G{=D*llo6EIx!}tTBQ`T>J*V?_+r#P@Fv@UkXOS@; zpkaFJ?J&oqR!zk+muWnQdtVN0x7st%9lVKvLX*5lgiR#D7t7i6KE+aloEFcilEXJ5 zdb1=Tgmm3*Upvup7T{CVs-aHcYG4i$_4>Gdd*S~!yy^*JNMexBmHy7XBYe9xOsX$= z&U9PUF-b-K;e#WHt-8E(+PCt$oY1?LG51{jU9r_uK0%qu4u#1{mqufuzz+Dst1jZA zkYL}*jjL#~&@}^Z0X2ufwpbayTBX@4!Fap=Z??uaJ>K-6a=Vh-A1plfsq1>#S>phv zTKz$AT1@9r*qLW0x#5@`T)1;PDJI~6F~qz9*}1$lrI{+H#Hg z)=WyxW+E@b$}NIdYA-ZU_%q*;uACxo-%KNzj678$Sghf~Kp{v`xzgOZ;W13}>aF&; zIDzheErT$elvVJ?hev>pEnM zX6S+vL@MJR%p4Q@4X78iuU&Y$eJvSNs^g_nFl#nRqbWA zsJJi$v!p)!)&B(s3o#JC*ic)0jCL{gqveLOAmTiykw zjg062Olzd-?xyv+UFGzihr8=P-hztIVw^zWPrqG84t{@q(__}23jX;)+4GR(Rm3fw zyA+xwZ*@h@^q4}v+2tG2sjm4p|EgrZ+svJKF#U?W%*l*~Y5i8BtLqR9?y6lEN&W?f zIaKZNx33>L9Y21gKqkj;_JDPR60*Xu0A@g3`gPiNA6BZoEb%Q1%oj_wUHv@VH9P!& z&uQW~OckX@M-HUaeSHYIiUT5vE(m2FU*z;1evg0hRRv6EQJ0!ITxSjQfpi2c4$yn$CA`zU{A&aKN70_`r>y&d5yw&oAQ1K;IiQ)9X=eEA&73U4C95{DSniL+L&QID> zmzCLf4RSmriVzK$c0ub^emnUQPbXPxN_3R%BTvoQhNeu9X_o3b~2XnbYRd0pGTgOf{v!1#8tb@-*+DFslL%g zWo26zpF)tg>h+zFMVoF%U|h{z(U`BJWenfe>-mC%jZ-6T37EhpZ&5qIVkOx}!&$^K zK62FAV^!;&j;D)Wgn5IB+%dry-)%mhhKq80Q+4wK+b|7*+008=M4lt=cavHU>pk7w zyHLc%IrH!Jqe<&fPM-2g2i77&4hvjhrR}Sqd&*Tw_02BU53S_j+{T=y6|B&avxnZZMF??N(VkJi@E5o)GmRUU^5 z!{cX$9%I&oZ=E`ciT~XnM=wbm+RAAf<&|%aG%gwmwmZIO>&n3@I#!^3uP(adXKEII zOzLxYkyRfh##pD*bsvRw_8c(MK39p~6;Yy>GWsbtJlZ#DAL7rSWnxSPaU3KhVaQt;_KOrjE#WVYDJf3Pt!Z=O2peV4lh&%S3(1ET)@ma&G;Awle3|p? zGLOGr01S1L`;&N%&&0$;Aq>8iwHrT4@kKi^zT={&M6i8QSJaJHa~+;*F$S0m$zW&_F98~&BJu-mj3yppjKSaSYgEW1U! ztZB>mZ>hfD^-F!U-o&gY@tkZtB1LIIR!p|QTH~0LWjq`cvwL;uO9fy*oIQ$bGJd;C zf2iH_F9L)O_ov=Ux>Ks+ovQszy4Up$fxDuCWxY!d;R7H0ESaXQO zZS7o;(@({9;qz}xvL3BpI()>c@qf|v7C=>Y-`nsbB8Vs=DM~5AK~lO~CFM|(0@4D~ z-6Gv_=sI+Fmw)XfQ^Z)(d`QCYF9A^~nd-lEe+G|~_u4NTtW!rSkbQ3UQ z83P)@BdqRHmWWrslq`sL);P~7Vp+*;-4*(e+h*i?DNr)RI_duDmS9yZ+o@L>4b~U8yB9CL`i14Hj|B9*@Bv zr<>H?8QU0>rJLY2Y&uH7pP>Ec0$qQ4_tN7MckopUH)e&4vICepc&j&m4M}ghfSTXp z7C!eEAToVC0DnyDy$F;s_{$srKl>otV{nB#DGOhNHt0f8g+kr#{Z~PO$&LR}7n&ij zE^!Y?#&KQS9l%`R+nN8W&%c@sDLBr2%GX_Uo;5P9ZlrkaEQ_L$pX6zejv?uSU__uN zEwvjCHnDBqQQMAFqd5*?kJB4E6-d>F%}zg;6fFhC7Pk$R4+c~{ zcVvJKJd7L!p`v$^z_@AYya0VKC10-0Bav&pI^wLOKOe>Yc>n5%lwUs(||_IFZn@(u=NS z8&^KJ)I0;uz9BR3vG3B&dj1_TOuQx}E`>P4pq%BXJ^1tIp_tW;9xYYUkgUwYE-hiv z=p3M_|ARx8&6-76HCy2CRz0B0u)iP1Q-GP1S)q z*dFh7Q2AZ*ZFy$acsjPnZE(COcFs?+uX2Y*g+#{$WySSO zmV-Yo&<@@La~<5VcS@zd`7&^5aHOiV(u2DrUM*u4uVnZgo||Pwu8#K@ajx`z3fyd~ zgFzcMlYX(Qr)_ZJE(XwSCO0-*T3VtcD?c{GF=m)I5QGV)W%Vys`%aS|YEoykg=oy*>BXc^-x~buSWU{D`)Be)9EB`-=@o+8@1JvfhlfU=n~sae)IgjPgK9@-{YtWwGdJR zrtXPP^jz%bhOy3Cgo?RMG9nN+S}R~{IQD~H-%S7W!keuNT=;}g8;5F)+O z$`N1vnt3F)wwYXJd0=mP7lXMKrxYzc{n9+ESBs};FrlH*R_fo){>VkQ`?KV)x$Pu; zEql9sT`~2Cb-?zp06|D*X6CZ5_U&APi|b;%nzj9w9{_?PE`CZSS@AXlQ}dRr7JBZh zSu);mMp{TCx$}wnO&8EtGnoz;c#()mR_AGSpCR?a?LQpE2F$aI+as4LSGb(-mX`5N zNcea}t8%0G&Yl=N6_!%9`sb z-!6YK^w>a^1VacXeaSnYp7}FUuJF&)6)s&AgEM^tH|vC~k~OiEeStIlwR-=eOCtk9U>DkBG#Y7r88 z1WW$aaEC-swJkhI%~n3!~JnAMLPp~NMKYma-m&X#>1MSi_g58 zutE5+fM-#zZR^bi?l_C38Zm31+WvhVgo{sUicM*N)2EleNCBd8y&RL$l%;fnF%wy# z(VyQ_9edyIJ0^YzDPG%ceava(J+>W{#IeXVbi~+&i5K{(58x{zvx;i)%@@A?zNBU~Su28Wj#nee!LL+^qs zu=2@$9t#bR;!m&%W`acAgG5F}iTAwCWDC3Qx-hO<_~!xT%IZ}k^D3`X1*rzbgAW!Wy`iFXASP`wKmFkYdzDOQ-aC2%DNZU6&=~mpeDO zdqRlVGL&zida_i12y5KbRL^Pcl?O+fL+uDZJt7h%JLq`FgbA7nPZu0?h5SDKQyiJ@8BNP`{J8x$ zf7sOG-}N1IxB&4oPuR$aH%TuaZs7z`2c(0={Cn_4Wq;gDDT#4vXSUzM%en*%Dk8>U z!#&Gk=667H4j=hRlJq@Q!{F-cg$!20uDc!=aTU+lZ1$dNq!z`nPT-#&93Nzv+$r8J z0~d&}XD@w)pd)L!nUBjVqfnxphSef5IprL;`nvS;>f!?j?vV7ZKmttG{KUwHa7met z1^^*d(t0n=Sse(2NaDVl)uFJ>harkn{1WsN$PH$I0A00mVuY)ao29hs><7*dTOL*E zH;vu`T(;XW4GsLR81I4IdP9tH3?cr44|e(PVfYd>o9U&bq6zqn^Ol-okJ`*Aq`#b< zo!j#2W$I}tw>HGz6qt9UPb1m=SKPOo9)u1d27)Z26li!2E?W2j>@=JbzkRPR!m3Z< z?11`K3mB0V<kLy$9o_~A_KMV6&1t?+wTwPpR%sla1T{CSen|yoRt8dU|RRzxrWHn%GU7IcZZ9h7+Y=M-tFU}$dkI>9^HU7NY|iCV5XB?4%B0cv#BP?y>4EwA zrT#`(L&S{=o{WTiwR)z8BFHx{^7&X&&@Dj|zGQ`LXv)V_x_I7TC?wgJ1EAIBHoG|L z(tZ< zbv?#C1wbgMt7}o>lZkrtTb4MdS*+oSiL-_AuAcovhx6VY`@`Up=LBw+YYTh9h4MDm zPXc=4a=3HKPt*lsgE=^!8(7waYc+f`z3H0$<;2Fyx}Qh>7i|M=u?_4YhDJGFoc<-6 zHOr^hk4lV|Y>m(lfF`myi+SK9Xcjl@C*AXlTt-GgQI^N0CU_KtU8YV+y%QYKmb%S` zvPelDf^n_m1~;QK$g3{w5ZJ{aFOHF7my=oe;EI?>T+=jW8TvHt{QH=-~3@VYO*(@m2Pjune zrvrv=8*>CWdmY$Y4PHaAsg~%!!cCmyzfFmb!xI`u({nP6O$~?WDo?S$9{?wtmKMEA z`b$djISe>gAGVA!@odd{4_V5TOEk_1uV5x ze|EgY+yVe8rd7I}jh{Se>G^VVALiVvZ>2kqFrr3zNzGh_84jdb-*2_dJ?@A-%t*H- zk@~AvB6FqfgVHnfOlMtNuU}wj3grn3$vX3;g&jlom1tiM6z82&I0V}0!yBkBU6_b8 z#}0lXg>$6=wsT^)=}QMZXB)FOAlo5i7jYHDd}s@#L29#jsj&?gvOloJ*^g#aT3fK$p_`n8|uZmm@Ut{g*Uv$g)(_}96i;T9+kXr z&;#CrGrs@;%=OO!8dUxz%lg3oY@6JI@_~VP7Y!btF6)e>GcigR{NaZXste(v)foFs z?mM%K%YxKM-!`fm{O}vUY(psX@CL8m$Dv=EtyayF|EOnqEpJXQOg~Kr}8A>xQ<` zDtoI7B?7GKP+wB(=sjjOb635Ac_Xf&pl_9XMLO>AOQk3NBd{7W!Edq%P+ldWf6wu)D|vu`;nocW`J2bPYlw4JRi+?2%`3zc*`Yt$tY5(- z?ef#z_iE_Xr?9rq<=p*|ppw=|r0V7}t18YPNc+|$oaKeU@7(&ZbGn$IMBJq^$v19t zV+YOIZZxZ(v?W=dzCTV9F%PP}{Ma@oK*S(?2ywz;$w=2Lw>}0m7LXNd+xP(i14a+X zs|(yCzsei=mG9&$Qe6yq)J;wjTxIi{9aD|1a9w?UZ%}5Akvzxk~ zAA-k_)ZdUzM`zz0C(LQ!af1#p>NgRR*q3F}WBL<_5b*Bp# zj(1DOR{il$)XpB_;f;Nt9I%G-!&}_0JapYqT=oZ5Q#@ci){DW!j4x!ky)uGEVF|>< zGev%*99sLlZ`@wz9(7$^AK^P*dYj4{C|2;MuvZGWR0Dq0!MG zIU+`f1BO&hMebf2E`(PA7<}*5f_uuG+7y=%K4%+KFh zL!*DBQQkYCx7n+5FNp?U_w}^R z+}}LLd{|Lx@ldlNCDqRX3m1F=k$q5QD{*m!)#2e2Pwp&-OVDP##~&(Fzwuud={J_X`sBG9FLM zNGb(naSI%A50*6K5D8^^GH)QaZ#XzOsHobTn*I?80M0Fl>Nc$b0X@kyBAn?E4qhyHZfrlI=F1PCxYeVSq+uo4ETz7&-3=}l*gjM5|R zwnX4*CN7h*;)9SXjRA;Ak8SP>OP`mW{5IR>0*-+K!h07E;=@7+|EZ8xrSBlPx2!MNSktM@G;fB)0rYIiF<&a_iy^bZC91SUO5gDI2?xGD`CKeW^+*!_;z zpgrdx^EY0trb_FX02Hl`N|+B)spN6AHQCC8@d#^nU#9uA;1ljghErYrd%PU)mY65UaJK%84cA(RB$nx1)D)zdMCUqCn-wZP9S)Oxb`Vt81cEFQBrLJq{NMS0Y&UW!Ja2iOI;|aCra1 z88PaGFcvBA`uzMqb4?>4agwhBi;cy22@;v%7?-$m$oPCSK2XKm@I?`g!h;ukf&4B_JXyTjL}w4}n+!NkBMXQq#;Mj4;6g?!hQyDQ2jwR6Qtt)<6;3gLBe;R&<>gnF9Cq>*=bQ)L7tiJ zS6$1LYlL9p@Gv)nJn!*wkUzh=mIL)ID!;9~oLqiE!9c>ldlVuJ2wZ?>nx6jhcbf<; zkJkqtU=oN)O7`^hI5|3!@;jd|DIP<7bq_yX`vI>oH*0VE$Hf<~xLT@X2QH~`xO@Nz ziZ1T{){-VsA2=jqakE@%Vb%jawfo+^%bIRwEREMcmZ`Dm)Ip35}ONF~4)0jueX%jG2K8eyN>6 z!!X%SsBCQ|>-%L6iXEb2?lbHrxu+~d(@Z`W-3IBn>}8pDBGG6=jRtoo+_GfEav+Q3 z*hj8fX|+Z@B_0P9Ef6G^9T@MZ#mug4o zZr?C6GBPs{wzi`FuR^l6vGGcJ%U|XphR4OlRasdHOsu7)C9P5+9=z}QztZ%R90wtG z2@-=JY>YKs2l_}Xa^iKcTDL!SaVb%$Qc7&+M5SE8ZoPb5f60x6*π2YZ4Nk~bv4 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

Lwsy`crzo) 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≪pHU+o$4V_RRh+|yMpSy#_je;fa$Ld&BTs4+kSRvmQEFA_>D4OC?laZ)(4eDcq`E? z(q#_l`$F7>*nzxF^=Tx1>ODwJx1Z8lAK5epPec59TXnv|F%z&>KXW%I(;;wPr|<+&oQ$6gQWM$=^<|&gJ_g@+l2Xx z?caL*PhcM(d?I?;>ud9u(5DgKzvqPXESR5VixdF!GtENO`RIVR*&#+^zCU?)b*HLSF23 zlX7ov^21hz1eH=(a*2*G;sdKb^BDY|2$g4m>VCeGTaseOBpk6t3FhhhK2!LiBe}$! zXXZ|kbW1YzsB`b`XpUJqdyq%&C{65o(3@6b-kPwg38Th6+?5eImYIqJ#jdC0-lq`z zZUz0@CC~@436Q7%eUGUAJ%lWXDv+g^8@3%uEg(B+Y4jHH7Knboj-~>>OcXTrpWTx4u+s;Uz z8ot+C!pNOoSJBQTkS?dR+Ket1YZZe|RQZeJ0_I^JT@pJ!0ZO>6Q9*v#c(S^swwIux zqJyM`=F9M@kgScaPcOLx+RRb>EJJnuO?chzpqebidMdy@Y?M;5Y{mw2K)Px3c)IsY zX2jv7rFDky$Pbs3CtK<1O|ZP80MpwJf6tI^rF%9;ce?&hU-lY{^8v^Clk$-SQrS`* zzUus+<1EFE#!mKe4R*=`KDsv1L|kJwW8>m-QZf>}mHA*0+ z%3m38?v^{<@oM4^Q#qT|4{)={kGN}kcAE-HuLW^y)(gs3=;oF4R^ENh%fHFoSCTd? zlg$+F5PAmmU3|T@Hh64!ZqV%A)V(xo@QkteskIBvyaB>X1&w+JJHm7CLU+52{WHqa z;{}`h-pq!cvVKybg}A;o6pW~#N7Vn8l*0pDLlJcjBYU3SAU0tJq~K>+^b446c!93w z7HS)8RzxRFgC_RLTz&oT@Q9z4HgN@GQqh_dWS4#>&q#lGt*TMz4_Z8 zt8Zv0H|z!ITxhPeX7}NftSe%b$nT4u3DrFDUbGQ|RnAq|Qz^w^AHjP?E@|hNn`VzT zSqmOr%u>bH)@H!Y?luJ_-H1AyU}UU1#$vW!LRu9m*8C|h97r7H(@)9lSjJ(dY3tbA zrOtPEbhr8zim#o_p4Q29EGp}m+|p&R4<8&=(bTri=>=5{yx#QLFQzrPk_zV(=#t?P zU^I2#hTsNM#Zt}Yp2y=G7^CLqNtT#jD^1fHhZ$f2x0~qd`{Gr>2bpzAr3RHg^RMNB z8yV(rXa^&y??va`Uuckx+bS;?_BC-HJ`w^U>~P+1e#KA5A$eEt6HBNLj;zQByun;L zb9M#=F$%*trz$P07wuDpM=U-)qlwiFzyUofKzpsOu;zhWOpV4PdsXNa(Hj5sZqO8R z=W;H37N@aqc5f4t44x84qD_wPVv28A;DHmqak1VfbBl5}^&L;{Zw=0d)J=YJ?Uxd~ zDUQIAX*g*4js3zy)McISC_qb$@2krC%YFAmQv?ft+bw;%5MmV6G|8lx<#)y2j#v%o zyW$l6 z=JWe|9QrU;9q|1l8|PWnd-jK{Z*9$(K@0nfYq(e3=H}`a2UEevR<+jL�Cr0|Xu` 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¬YX!YhT9p_SoF=u7z3;oVWkUZ}X1PB-BmR!(j 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

=8{9jVAqnRAPp`BJ1`4!j(rEq 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 Date: Tue, 21 Nov 2023 14:51:15 +0100 Subject: [PATCH 045/219] Added CICP profile to image metadata --- src/ImageSharp/Metadata/ImageFrameMetadata.cs | 7 +++++++ src/ImageSharp/Metadata/ImageMetadata.cs | 7 +++++++ 2 files changed, 14 insertions(+) diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs index 03f628afa3..f02ef39c48 100644 --- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs +++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Metadata.Profiles.CICP; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; @@ -43,6 +44,7 @@ public sealed class ImageFrameMetadata : IDeepCloneable this.IccProfile = other.IccProfile?.DeepClone(); this.IptcProfile = other.IptcProfile?.DeepClone(); this.XmpProfile = other.XmpProfile?.DeepClone(); + this.CicpProfile = other.CicpProfile?.DeepClone(); } /// @@ -65,6 +67,11 @@ public sealed class ImageFrameMetadata : IDeepCloneable /// public IptcProfile? IptcProfile { get; set; } + /// + /// Gets or sets the CICP profile + /// + public CicpProfile? CicpProfile { get; set; } + /// public ImageFrameMetadata DeepClone() => new(this); diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index f54fc5c7ae..c6ff6fe73e 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Metadata.Profiles.CICP; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; @@ -68,6 +69,7 @@ public sealed class ImageMetadata : IDeepCloneable this.IccProfile = other.IccProfile?.DeepClone(); this.IptcProfile = other.IptcProfile?.DeepClone(); this.XmpProfile = other.XmpProfile?.DeepClone(); + this.CicpProfile = other.CicpProfile?.DeepClone(); // NOTE: This clone is actually shallow but we share the same format // instances for all images in the configuration. @@ -157,6 +159,11 @@ public sealed class ImageMetadata : IDeepCloneable ///

B|1o_ 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

public IptcProfile? IptcProfile { get; set; } + /// + /// Gets or sets the CICP profile. + /// + public CicpProfile? CicpProfile { get; set; } + /// /// Gets the original format, if any, the image was decode from. /// From b12badadee65b0270f20741624e45875929abb1f Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Tue, 21 Nov 2023 14:51:46 +0100 Subject: [PATCH 046/219] Added CICP metadata handling to PNG de/encoder --- src/ImageSharp/Formats/Png/PngChunkType.cs | 6 ++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 33 +++++++++++++++++++ src/ImageSharp/Formats/Png/PngEncoderCore.cs | 21 ++++++++++++ .../Formats/Png/PngChunkTypeTests.cs | 1 + 4 files changed, 61 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngChunkType.cs b/src/ImageSharp/Formats/Png/PngChunkType.cs index a008bf8ea2..cc41cf5a29 100644 --- a/src/ImageSharp/Formats/Png/PngChunkType.cs +++ b/src/ImageSharp/Formats/Png/PngChunkType.cs @@ -140,6 +140,12 @@ internal enum PngChunkType : uint /// cHRM (Single) Chroma = 0x6348524d, + /// + /// If this chunk is present, it specifies the color space, transfer function, matrix coefficients of the image + /// using the code points specified in [ITU-T-H.273] + /// + Cicp = 0x63494350, + /// /// This chunk is an ancillary chunk as defined in the PNG Specification. /// It must appear before the first IDAT chunk within a valid PNG stream. diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index d8305a3f57..acb97ed893 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -16,6 +16,7 @@ using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.Metadata.Profiles.CICP; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; @@ -183,6 +184,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals case PngChunkType.Gamma: ReadGammaChunk(pngMetadata, chunk.Data.GetSpan()); break; + case PngChunkType.Cicp: + ReadCicpChunk(metadata, chunk.Data.GetSpan()); + break; case PngChunkType.FrameControl: frameCount++; if (frameCount == this.maxFrames) @@ -352,6 +356,15 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ReadGammaChunk(pngMetadata, chunk.Data.GetSpan()); break; + case PngChunkType.Cicp: + if (this.colorMetadataOnly) + { + this.SkipChunkDataAndCrc(chunk); + break; + } + + ReadCicpChunk(metadata, chunk.Data.GetSpan()); + break; case PngChunkType.FrameControl: ++frameCount; if (frameCount == this.maxFrames) @@ -1392,6 +1405,26 @@ internal sealed class PngDecoderCore : IImageDecoderInternals return false; } + /// + /// Reads the CICP color profile chunk. + /// + /// The metadata. + /// The bytes containing the profile. + private static void ReadCicpChunk(ImageMetadata metadata, ReadOnlySpan data) + { + if (data.Length < 4) + { + // Ignore invalid cICP chunks. + return; + } + + byte colorPrimaries = data[0]; + byte transferFunction = data[1]; + byte matrixCoefficients = data[2]; + bool? fullRange = data[3] == 1 ? true : data[3] == 0 ? false : null; + metadata.CicpProfile = new CicpProfile(colorPrimaries, transferFunction, matrixCoefficients, fullRange); + } + /// /// Reads exif data encoded into a text chunk with the name "raw profile type exif". /// This method was used by ImageMagick, exiftool, exiv2, digiKam, etc, before the diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 04e3b1d840..a86fd17cca 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -166,6 +166,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable this.WriteHeaderChunk(stream); this.WriteGammaChunk(stream); + this.WriteCicpChunk(stream, metadata); this.WriteColorProfileChunk(stream, metadata); this.WritePaletteChunk(stream, quantized); this.WriteTransparencyChunk(stream, pngMetadata); @@ -773,6 +774,26 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable this.WriteChunk(stream, PngChunkType.InternationalText, payload); } + /// + /// Writes the CICP profile chunk + /// + /// The containing image data. + /// The image meta data. + private void WriteCicpChunk(Stream stream, ImageMetadata metaData) + { + if (metaData.CicpProfile is null) + { + return; + } + + Span outputBytes = this.chunkDataBuffer.Span[..4]; + outputBytes[0] = (byte)metaData.CicpProfile.ColorPrimaries; + outputBytes[1] = (byte)metaData.CicpProfile.TransferCharacteristics; + outputBytes[2] = (byte)metaData.CicpProfile.MatrixCoefficients; + outputBytes[3] = (byte)(metaData.CicpProfile.FullRange ? 1 : 0); + this.WriteChunk(stream, PngChunkType.Cicp, outputBytes); + } + /// /// Writes the color profile chunk. /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs index 06cb079e5b..02e8dc7dfb 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngChunkTypeTests.cs @@ -29,6 +29,7 @@ public class PngChunkTypeTests Assert.Equal(PngChunkType.Background, GetType("bKGD")); Assert.Equal(PngChunkType.EmbeddedColorProfile, GetType("iCCP")); Assert.Equal(PngChunkType.StandardRgbColourSpace, GetType("sRGB")); + Assert.Equal(PngChunkType.Cicp, GetType("cICP")); Assert.Equal(PngChunkType.SignificantBits, GetType("sBIT")); Assert.Equal(PngChunkType.Histogram, GetType("hIST")); Assert.Equal(PngChunkType.SuggestedPalette, GetType("sPLT")); From a42f6b65daf61c19e07ee3ead2b5c128f80f115d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 23 Nov 2023 13:41:46 +1000 Subject: [PATCH 047/219] Enable dedup for png --- src/ImageSharp/Formats/AnimationUtilities.cs | 11 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 2 + src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 - .../Formats/Gif/MetadataExtensions.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 169 +++++++++--------- 5 files changed, 97 insertions(+), 89 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 1bca34eae4..ee9a85ac43 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -85,11 +85,12 @@ internal static class AnimationUtilities int m = Avx2.MoveMask(neq.AsByte()); if (m != 0) { - // If is diff is found, the left side is marked by the min of previously found left side and the diff position. - // The right is the max of the previously found right side and the diff position + 1. - int diff = (int)(i + (uint)(BitOperations.TrailingZeroCount(m) / size)); - left = Math.Min(left, diff); - right = Math.Max(right, diff + 1); + // If is diff is found, the left side is marked by the min of previously found left side and the start position. + // The right is the max of the previously found right side and the end position. + int start = i + (BitOperations.TrailingZeroCount(m) / size); + int end = i + (2 - (BitOperations.LeadingZeroCount((uint)m) / size)); + left = Math.Min(left, start); + right = Math.Max(right, end); hasRowDiff = true; hasDiff = true; } diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index bc41c89dcf..aecbbbbc71 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -797,6 +797,8 @@ internal sealed class GifDecoderCore : IImageDecoderInternals this.gifMetadata.GlobalColorTable = colorTable; } } + + this.gifMetadata.BackgroundColorIndex = this.logicalScreenDescriptor.BackgroundColorIndex; } private unsafe struct ScratchBuffer diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 2bc3e53f78..24bb3c00e1 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -245,8 +245,6 @@ internal sealed class GifEncoderCore : IImageEncoderInternals ImageFrame previousFrame = image.Frames.RootFrame; // This frame is reused to store de-duplicated pixel buffers. - // This is more expensive memory-wise than de-duplicating indexed buffer but allows us to deduplicate - // frames using both local and global palettes. using ImageFrame encodingFrame = new(previousFrame.Configuration, previousFrame.Size()); for (int i = 1; i < image.Frames.Count; i++) diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index c7f9f84c80..1b9b6ac58c 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -83,7 +83,7 @@ public static partial class MetadataExtensions ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), DisposalMode = GetMode(source.DisposalMethod), - BlendMode = FrameBlendMode.Source, + BlendMode = FrameBlendMode.Over, }; private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a779718a0b..016c422337 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; @@ -118,6 +119,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// private IQuantizer? quantizer; + /// + /// Any explicit quantized transparent index provided by the background color. + /// + private int derivedTransparencyIndex = -1; + /// /// Initializes a new instance of the class. /// @@ -164,7 +170,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable } // Do not move this. We require an accurate bit depth for the header chunk. - IndexedImageFrame? quantized = this.CreateQuantizedImageAndUpdateBitDepth(pngMetadata, currentFrame, null); + IndexedImageFrame? quantized = this.CreateQuantizedImageAndUpdateBitDepth( + pngMetadata, + currentFrame, + currentFrame.Bounds(), + null); this.WriteHeaderChunk(stream); this.WriteGammaChunk(stream); @@ -180,44 +190,51 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); - // TODO: We should attempt to optimize the output by clipping the indexed result to - // non-transparent bounds. That way we can assign frame control bounds and encode - // less data. See GifEncoder for the implementation there. - // Write the first frame. - FrameControl frameControl = this.WriteFrameControlChunk(stream, currentFrame, 0); - this.WriteDataChunks(frameControl, currentFrame, quantized, stream, false); + PngFrameMetadata frameMetadata = GetPngFrameMetadata(currentFrame); + PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); // Capture the global palette for reuse on subsequent frames. ReadOnlyMemory? previousPalette = quantized?.Palette.ToArray(); // Write following frames. uint increment = 0; + ImageFrame previousFrame = image.Frames.RootFrame; + + // This frame is reused to store de-duplicated pixel buffers. + using ImageFrame encodingFrame = new(image.Configuration, previousFrame.Size()); + for (int i = 1; i < image.Frames.Count; i++) { currentFrame = image.Frames[i]; + frameMetadata = GetPngFrameMetadata(currentFrame); + + ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + if (clearTransparency) { - // Dispose of previous clone and reassign. - clonedFrame?.Dispose(); - currentFrame = clonedFrame = currentFrame.Clone(); - ClearTransparentPixels(currentFrame); + ClearTransparentPixels(encodingFrame); } - // Each frame control sequence number must be incremented by the - // number of frame data chunks that follow. - frameControl = this.WriteFrameControlChunk(stream, currentFrame, (uint)i + increment); + // Each frame control sequence number must be incremented by the number of frame data chunks that follow. + frameControl = this.WriteFrameControlChunk(stream, frameMetadata, bounds, (uint)i + increment); // Dispose of previous quantized frame and reassign. quantized?.Dispose(); - quantized = this.CreateQuantizedImageAndUpdateBitDepth(pngMetadata, currentFrame, previousPalette); - increment += this.WriteDataChunks(frameControl, currentFrame, quantized, stream, true); + quantized = this.CreateQuantizedImageAndUpdateBitDepth(pngMetadata, encodingFrame, bounds, previousPalette); + increment += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true); + + previousFrame = currentFrame; + previousDisposal = frameMetadata.DisposalMethod; } } else { FrameControl frameControl = new((uint)this.width, (uint)this.height); - this.WriteDataChunks(frameControl, currentFrame, quantized, stream, false); + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); } this.WriteEndChunk(stream); @@ -317,15 +334,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// The type of the pixel. /// The image metadata. /// The frame to quantize. + /// The area of interest within the frame. /// Any previously derived palette. /// The quantized image. private IndexedImageFrame? CreateQuantizedImageAndUpdateBitDepth( PngMetadata metadata, ImageFrame frame, + Rectangle bounds, ReadOnlyMemory? previousPalette) where TPixel : unmanaged, IPixel { - IndexedImageFrame? quantized = this.CreateQuantizedFrame(this.encoder, this.colorType, this.bitDepth, metadata, frame, previousPalette); + IndexedImageFrame? quantized = this.CreateQuantizedFrame(this.encoder, this.colorType, this.bitDepth, metadata, frame, bounds, previousPalette); this.bitDepth = CalculateBitDepth(this.colorType, this.bitDepth, quantized); return quantized; } @@ -1033,20 +1052,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// Writes the animation control chunk to the stream. /// /// The containing image data. - /// The image frame. + /// The frame metadata. + /// The frame area of interest. /// The frame sequence number. - private FrameControl WriteFrameControlChunk(Stream stream, ImageFrame imageFrame, uint sequenceNumber) - where TPixel : unmanaged, IPixel + private FrameControl WriteFrameControlChunk(Stream stream, PngFrameMetadata frameMetadata, Rectangle bounds, uint sequenceNumber) { - PngFrameMetadata frameMetadata = GetPngFrameMetadata(imageFrame); - - // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. FrameControl fcTL = new( sequenceNumber: sequenceNumber, - width: (uint)imageFrame.Width, - height: (uint)imageFrame.Height, - xOffset: 0, - yOffset: 0, + width: (uint)bounds.Width, + height: (uint)bounds.Height, + xOffset: (uint)bounds.Left, + yOffset: (uint)bounds.Top, delayNumerator: (ushort)frameMetadata.FrameDelay.Numerator, delayDenominator: (ushort)frameMetadata.FrameDelay.Denominator, disposeOperation: frameMetadata.DisposalMethod, @@ -1064,11 +1080,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable ///
/// The pixel format. /// The frame control - /// The frame. + /// The image frame. /// The quantized pixel data. Can be null. /// The stream. /// Is writing fdAT or IDAT. - private uint WriteDataChunks(FrameControl frameControl, ImageFrame pixels, IndexedImageFrame? quantized, Stream stream, bool isFrame) + private uint WriteDataChunks(FrameControl frameControl, Buffer2DRegion frame, IndexedImageFrame? quantized, Stream stream, bool isFrame) where TPixel : unmanaged, IPixel { byte[] buffer; @@ -1082,16 +1098,16 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { if (quantized is not null) { - this.EncodeAdam7IndexedPixels(frameControl, quantized, deflateStream); + this.EncodeAdam7IndexedPixels(quantized, deflateStream); } else { - this.EncodeAdam7Pixels(frameControl, pixels, deflateStream); + this.EncodeAdam7Pixels(frame, deflateStream); } } else { - this.EncodePixels(frameControl, pixels, quantized, deflateStream); + this.EncodePixels(frame, quantized, deflateStream); } } @@ -1156,54 +1172,43 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// Encodes the pixels. ///
/// The type of the pixel. - /// The frame control - /// The pixels. - /// The quantized pixels span. + /// The image frame pixel buffer. + /// The quantized pixels. /// The deflate stream. - private void EncodePixels(FrameControl frameControl, ImageFrame pixels, IndexedImageFrame? quantized, ZlibDeflateStream deflateStream) + private void EncodePixels(Buffer2DRegion pixels, IndexedImageFrame? quantized, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { - int width = (int)frameControl.Width; - int height = (int)frameControl.Height; - - int bytesPerScanline = this.CalculateScanlineLength(width); + int bytesPerScanline = this.CalculateScanlineLength(pixels.Width); int filterLength = bytesPerScanline + 1; this.AllocateScanlineBuffers(bytesPerScanline); using IMemoryOwner filterBuffer = this.memoryAllocator.Allocate(filterLength, AllocationOptions.Clean); using IMemoryOwner attemptBuffer = this.memoryAllocator.Allocate(filterLength, AllocationOptions.Clean); - pixels.ProcessPixelRows(accessor => + Span filter = filterBuffer.GetSpan(); + Span attempt = attemptBuffer.GetSpan(); + for (int y = 0; y < pixels.Height; y++) { - Span filter = filterBuffer.GetSpan(); - Span attempt = attemptBuffer.GetSpan(); - for (int y = (int)frameControl.YOffset; y < frameControl.YMax; y++) - { - this.CollectAndFilterPixelRow(accessor.GetRowSpan(y), ref filter, ref attempt, quantized, y); - deflateStream.Write(filter); - this.SwapScanlineBuffers(); - } - }); + this.CollectAndFilterPixelRow(pixels.DangerousGetRowSpan(y), ref filter, ref attempt, quantized, y); + deflateStream.Write(filter); + this.SwapScanlineBuffers(); + } } /// /// Interlaced encoding the pixels. /// /// The type of the pixel. - /// The frame control - /// The image frame. + /// The image frame pixel buffer. /// The deflate stream. - private void EncodeAdam7Pixels(FrameControl frameControl, ImageFrame frame, ZlibDeflateStream deflateStream) + private void EncodeAdam7Pixels(Buffer2DRegion pixels, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { - int width = (int)frameControl.XMax; - int height = (int)frameControl.YMax; - Buffer2D pixelBuffer = frame.PixelBuffer; for (int pass = 0; pass < 7; pass++) { - int startRow = Adam7.FirstRow[pass] + (int)frameControl.YOffset; - int startCol = Adam7.FirstColumn[pass] + (int)frameControl.XOffset; - int blockWidth = Adam7.ComputeBlockWidth(width, pass); + int startRow = Adam7.FirstRow[pass]; + int startCol = Adam7.FirstColumn[pass]; + int blockWidth = Adam7.ComputeBlockWidth(pixels.Width, pass); int bytesPerScanline = this.bytesPerPixel <= 1 ? ((blockWidth * this.bitDepth) + 7) / 8 @@ -1220,13 +1225,13 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable Span filter = filterBuffer.GetSpan(); Span attempt = attemptBuffer.GetSpan(); - for (int row = startRow; row < height; row += Adam7.RowIncrement[pass]) + for (int row = startRow; row < pixels.Height; row += Adam7.RowIncrement[pass]) { // Collect pixel data - Span srcRow = pixelBuffer.DangerousGetRowSpan(row); - for (int col = startCol, i = 0; col < frameControl.XMax; col += Adam7.ColumnIncrement[pass]) + Span srcRow = pixels.DangerousGetRowSpan(row); + for (int col = startCol, i = 0; col < pixels.Width; col += Adam7.ColumnIncrement[pass], i++) { - block[i++] = srcRow[col]; + block[i] = srcRow[col]; } // Encode data @@ -1244,19 +1249,16 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// Interlaced encoding the quantized (indexed, with palette) pixels. ///
/// The type of the pixel. - /// The frame control /// The quantized. /// The deflate stream. - private void EncodeAdam7IndexedPixels(FrameControl frameControl, IndexedImageFrame quantized, ZlibDeflateStream deflateStream) + private void EncodeAdam7IndexedPixels(IndexedImageFrame quantized, ZlibDeflateStream deflateStream) where TPixel : unmanaged, IPixel { - int width = (int)frameControl.Width; - int endRow = (int)frameControl.YMax; for (int pass = 0; pass < 7; pass++) { - int startRow = Adam7.FirstRow[pass] + (int)frameControl.YOffset; - int startCol = Adam7.FirstColumn[pass] + (int)frameControl.XOffset; - int blockWidth = Adam7.ComputeBlockWidth(width, pass); + int startRow = Adam7.FirstRow[pass]; + int startCol = Adam7.FirstColumn[pass]; + int blockWidth = Adam7.ComputeBlockWidth(quantized.Width, pass); int bytesPerScanline = this.bytesPerPixel <= 1 ? ((blockWidth * this.bitDepth) + 7) / 8 @@ -1274,16 +1276,13 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable Span filter = filterBuffer.GetSpan(); Span attempt = attemptBuffer.GetSpan(); - for (int row = startRow; row < endRow; row += Adam7.RowIncrement[pass]) + for (int row = startRow; row < quantized.Height; row += Adam7.RowIncrement[pass]) { // Collect data ReadOnlySpan srcRow = quantized.DangerousGetRowSpan(row); - for (int col = startCol, i = 0; - col < frameControl.XMax; - col += Adam7.ColumnIncrement[pass]) + for (int col = startCol, i = 0; col < quantized.Width; col += Adam7.ColumnIncrement[pass], i++) { block[i] = srcRow[col]; - i++; } // Encode data @@ -1455,6 +1454,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// The bits per component. /// The image metadata. /// The frame to quantize. + /// The frame area of interest. /// Any previously derived palette. private IndexedImageFrame? CreateQuantizedFrame( QuantizingImageEncoder encoder, @@ -1462,6 +1462,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable byte bitDepth, PngMetadata metadata, ImageFrame frame, + Rectangle bounds, ReadOnlyMemory? previousPalette) where TPixel : unmanaged, IPixel { @@ -1473,9 +1474,13 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (previousPalette is not null) { // Use the previously derived palette created by quantizing the root frame to quantize the current frame. - using PaletteQuantizer paletteQuantizer = new(this.configuration, this.quantizer!.Options, previousPalette.Value, -1); + using PaletteQuantizer paletteQuantizer = new( + this.configuration, + this.quantizer!.Options, + previousPalette.Value, + this.derivedTransparencyIndex); paletteQuantizer.BuildPalette(encoder.PixelSamplingStrategy, frame); - return paletteQuantizer.QuantizeFrame(frame, frame.Bounds()); + return paletteQuantizer.QuantizeFrame(frame, bounds); } // Use the metadata to determine what quantization depth to use if no quantizer has been set. @@ -1483,8 +1488,10 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { if (metadata.ColorTable is not null) { - // Use the provided palette. The caller is responsible for setting values. - this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value); + // We can use the color data from the decoded metadata here. + // We avoid dithering by default to preserve the original colors. + this.derivedTransparencyIndex = metadata.ColorTable.Value.Span.IndexOf(Color.Transparent); + this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }, this.derivedTransparencyIndex); } else { @@ -1496,7 +1503,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable using IQuantizer frameQuantizer = this.quantizer.CreatePixelSpecificQuantizer(frame.Configuration); frameQuantizer.BuildPalette(encoder.PixelSamplingStrategy, frame); - return frameQuantizer.QuantizeFrame(frame, frame.Bounds()); + return frameQuantizer.QuantizeFrame(frame, bounds); } /// From cc0727b286ba760003e719b07b3a0c84fd6eafa7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 23 Nov 2023 23:40:10 +1000 Subject: [PATCH 048/219] Add dedup to webp --- src/ImageSharp/Formats/Webp/AlphaEncoder.cs | 37 +++++----- .../Formats/Webp/BitWriter/BitWriterBase.cs | 5 +- .../Formats/Webp/Chunks/WebpFrameData.cs | 10 +-- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 69 ++++++++---------- .../Formats/Webp/Lossy/Vp8Encoder.cs | 60 ++++++++------- .../Formats/Webp/Lossy/YuvConversion.cs | 15 ++-- .../Formats/Webp/WebpAnimationDecoder.cs | 2 +- .../Formats/Webp/WebpEncoderCore.cs | 73 +++++++++++++++---- .../Formats/WebP/YuvConversionTests.cs | 5 +- 9 files changed, 154 insertions(+), 122 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs index cbd2aa8e7f..46030dde32 100644 --- a/src/ImageSharp/Formats/Webp/AlphaEncoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaEncoder.cs @@ -27,7 +27,7 @@ internal static class AlphaEncoder /// The size in bytes of the alpha data. /// The encoded alpha data. public static IMemoryOwner EncodeAlpha( - ImageFrame frame, + Buffer2DRegion frame, Configuration configuration, MemoryAllocator memoryAllocator, bool skipMetadata, @@ -35,8 +35,6 @@ internal static class AlphaEncoder out int size) where TPixel : unmanaged, IPixel { - int width = frame.Width; - int height = frame.Height; IMemoryOwner alphaData = ExtractAlphaChannel(frame, configuration, memoryAllocator); if (compress) @@ -46,8 +44,8 @@ internal static class AlphaEncoder using Vp8LEncoder lossLessEncoder = new( memoryAllocator, configuration, - width, - height, + frame.Width, + frame.Height, quality, skipMetadata, effort, @@ -58,14 +56,14 @@ internal static class AlphaEncoder // The transparency information will be stored in the green channel of the ARGB quadruplet. // The green channel is allowed extra transformation steps in the specification -- unlike the other channels, // that can improve compression. - using ImageFrame alphaAsFrame = DispatchAlphaToGreen(frame, alphaData.GetSpan()); + using ImageFrame alphaAsFrame = DispatchAlphaToGreen(configuration, frame, alphaData.GetSpan()); - size = lossLessEncoder.EncodeAlphaImageData(alphaAsFrame, alphaData); + size = lossLessEncoder.EncodeAlphaImageData(alphaAsFrame.PixelBuffer.GetRegion(), alphaData); return alphaData; } - size = width * height; + size = frame.Width * frame.Height; return alphaData; } @@ -73,25 +71,28 @@ internal static class AlphaEncoder /// Store the transparency in the green channel. /// /// The pixel format. - /// The to encode from. + /// The configuration. + /// The pixel buffer to encode from. /// A byte sequence of length width * height, containing all the 8-bit transparency values in scan order. /// The transparency frame. - private static ImageFrame DispatchAlphaToGreen(ImageFrame frame, Span alphaData) + private static ImageFrame DispatchAlphaToGreen(Configuration configuration, Buffer2DRegion frame, Span alphaData) where TPixel : unmanaged, IPixel { int width = frame.Width; int height = frame.Height; - ImageFrame alphaAsFrame = new ImageFrame(Configuration.Default, width, height); + ImageFrame alphaAsFrame = new(configuration, width, height); for (int y = 0; y < height; y++) { - Memory rowBuffer = alphaAsFrame.DangerousGetPixelRowMemory(y); - Span pixelRow = rowBuffer.Span; + Memory rowBuffer = alphaAsFrame.DangerousGetPixelRowMemory(y); + Span pixelRow = rowBuffer.Span; Span alphaRow = alphaData.Slice(y * width, width); + + // TODO: This can be probably simd optimized. for (int x = 0; x < width; x++) { // Leave A/R/B channels zero'd. - pixelRow[x] = new Rgba32(0, alphaRow[x], 0, 0); + pixelRow[x] = new Bgra32(0, alphaRow[x], 0, 0); } } @@ -106,12 +107,12 @@ internal static class AlphaEncoder /// The global configuration. /// The memory manager. /// A byte sequence of length width * height, containing all the 8-bit transparency values in scan order. - private static IMemoryOwner ExtractAlphaChannel(ImageFrame frame, Configuration configuration, MemoryAllocator memoryAllocator) + private static IMemoryOwner ExtractAlphaChannel(Buffer2DRegion frame, Configuration configuration, MemoryAllocator memoryAllocator) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = frame.PixelBuffer; - int height = frame.Height; int width = frame.Width; + int height = frame.Height; + IMemoryOwner alphaDataBuffer = memoryAllocator.Allocate(width * height); Span alphaData = alphaDataBuffer.GetSpan(); @@ -120,7 +121,7 @@ internal static class AlphaEncoder for (int y = 0; y < height; y++) { - Span rowSpan = imageBuffer.DangerousGetRowSpan(y); + Span rowSpan = frame.DangerousGetRowSpan(y); PixelOperations.Instance.ToRgba32(configuration, rowSpan, rgbaRow); int offset = y * width; for (int x = 0; x < width; x++) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 49b059b078..9ffda0f51f 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Diagnostics; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Metadata.Profiles.Exif; @@ -100,9 +99,7 @@ internal abstract class BitWriterBase bool hasAnimation) { // Write file size later - long pos = RiffHelper.BeginWriteRiffFile(stream, WebpConstants.WebpFourCc); - - Debug.Assert(pos is 4, "Stream should be written from position 0."); + RiffHelper.BeginWriteRiffFile(stream, WebpConstants.WebpFourCc); // Write VP8X, header if necessary. bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha || hasAnimation; diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index 230f69c32d..c8c4a74a00 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -83,7 +83,7 @@ internal readonly struct WebpFrameData ///
public WebpDisposalMethod DisposalMethod { get; } - public Rectangle Bounds => new((int)this.X * 2, (int)this.Y * 2, (int)this.Width, (int)this.Height); + public Rectangle Bounds => new((int)this.X, (int)this.Y, (int)this.Width, (int)this.Height); /// /// Writes the animation frame() to the stream. @@ -107,8 +107,8 @@ internal readonly struct WebpFrameData long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.FrameData); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.X); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Y); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.X / 2); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Y / 2); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Width - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Height - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Duration); @@ -128,8 +128,8 @@ internal readonly struct WebpFrameData WebpFrameData data = new( dataSize: WebpChunkParsingUtils.ReadChunkSize(stream, buffer), - x: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), - y: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), + x: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2, + y: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) * 2, width: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, height: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer) + 1, duration: WebpChunkParsingUtils.ReadUInt24LittleEndian(stream, buffer), diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index b9e2519fa4..518c09ff4d 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -240,7 +240,7 @@ internal class Vp8LEncoder : IDisposable public void EncodeHeader(Image image, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { - // Write bytes from the bitwriter buffer to the stream. + // Write bytes from the bit-writer buffer to the stream. ImageMetadata metadata = image.Metadata; metadata.SyncProfiles(); @@ -267,7 +267,7 @@ internal class Vp8LEncoder : IDisposable public void EncodeFooter(Image image, Stream stream) where TPixel : unmanaged, IPixel { - // Write bytes from the bitwriter buffer to the stream. + // Write bytes from the bit-writer buffer to the stream. ImageMetadata metadata = image.Metadata; ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; @@ -280,26 +280,25 @@ internal class Vp8LEncoder : IDisposable /// Encodes the image as lossless webp to the specified stream. /// /// The pixel format. - /// The to encode from. + /// The image frame to encode from. + /// The region of interest within the frame to encode. + /// The frame metadata. /// The to encode the image data to. /// Flag indicating, if an animation parameter is present. - public void Encode(ImageFrame frame, Stream stream, bool hasAnimation) + public void Encode(ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { - int width = frame.Width; - int height = frame.Height; - // Convert image pixels to bgra array. - bool hasAlpha = this.ConvertPixelsToBgra(frame, width, height); + bool hasAlpha = this.ConvertPixelsToBgra(frame.PixelBuffer.GetRegion(bounds)); // Write the image size. - this.WriteImageSize(width, height); + this.WriteImageSize(bounds.Width, bounds.Height); // Write the non-trivial Alpha flag and lossless version. this.WriteAlphaAndVersion(hasAlpha); // Encode the main image stream. - this.EncodeStream(frame); + this.EncodeStream(bounds.Width, bounds.Height); this.bitWriter.Finish(); @@ -307,21 +306,18 @@ internal class Vp8LEncoder : IDisposable if (hasAnimation) { - WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(frame); - - // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = new WebpFrameData( - 0, - 0, - (uint)frame.Width, - (uint)frame.Height, + (uint)bounds.Left, + (uint)bounds.Top, + (uint)bounds.Width, + (uint)bounds.Height, frameMetadata.FrameDelay, frameMetadata.BlendMethod, frameMetadata.DisposalMethod) .WriteHeaderTo(stream); } - // Write bytes from the bitwriter buffer to the stream. + // Write bytes from the bit-writer buffer to the stream. this.bitWriter.WriteEncodedImageToStream(stream); if (hasAnimation) @@ -334,12 +330,12 @@ internal class Vp8LEncoder : IDisposable /// Encodes the alpha image data using the webp lossless compression. ///
/// The type of the pixel. - /// The to encode from. + /// The alpha-pixel data to encode from. /// The destination buffer to write the encoded alpha data to. /// The size of the compressed data in bytes. /// If the size of the data is the same as the pixel count, the compression would not yield in smaller data and is left uncompressed. /// - public int EncodeAlphaImageData(ImageFrame frame, IMemoryOwner alphaData) + public int EncodeAlphaImageData(Buffer2DRegion frame, IMemoryOwner alphaData) where TPixel : unmanaged, IPixel { int width = frame.Width; @@ -347,10 +343,10 @@ internal class Vp8LEncoder : IDisposable int pixelCount = width * height; // Convert image pixels to bgra array. - this.ConvertPixelsToBgra(frame, width, height); + this.ConvertPixelsToBgra(frame); // The image-stream will NOT contain any headers describing the image dimension, the dimension is already known. - this.EncodeStream(frame); + this.EncodeStream(width, height); this.bitWriter.Finish(); int size = this.bitWriter.NumBytes; if (size >= pixelCount) @@ -364,7 +360,7 @@ internal class Vp8LEncoder : IDisposable } /// - /// Writes the image size to the bitwriter buffer. + /// Writes the image size to the bit writer buffer. /// /// The input image width. /// The input image height. @@ -381,7 +377,7 @@ internal class Vp8LEncoder : IDisposable } /// - /// Writes a flag indicating if alpha channel is used and the VP8L version to the bitwriter buffer. + /// Writes a flag indicating if alpha channel is used and the VP8L version to the bit-writer buffer. /// /// Indicates if a alpha channel is present. private void WriteAlphaAndVersion(bool hasAlpha) @@ -393,14 +389,10 @@ internal class Vp8LEncoder : IDisposable /// /// Encodes the image stream using lossless webp format. /// - /// The pixel type. - /// The frame to encode. - private void EncodeStream(ImageFrame frame) - where TPixel : unmanaged, IPixel + /// The image frame width. + /// The image frame height. + private void EncodeStream(int width, int height) { - int width = frame.Width; - int height = frame.Height; - Span bgra = this.Bgra.GetSpan(); Span encodedData = this.EncodedData.GetSpan(); bool lowEffort = this.method == 0; @@ -508,23 +500,20 @@ internal class Vp8LEncoder : IDisposable /// Converts the pixels of the image to bgra. ///
/// The type of the pixels. - /// The frame to convert. - /// The width of the image. - /// The height of the image. + /// The frame pixel buffer to convert. /// true, if the image is non opaque. - private bool ConvertPixelsToBgra(ImageFrame frame, int width, int height) + private bool ConvertPixelsToBgra(Buffer2DRegion pixels) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = frame.PixelBuffer; bool nonOpaque = false; Span bgra = this.Bgra.GetSpan(); Span bgraBytes = MemoryMarshal.Cast(bgra); - int widthBytes = width * 4; - for (int y = 0; y < height; y++) + int widthBytes = pixels.Width * 4; + for (int y = 0; y < pixels.Height; y++) { - Span rowSpan = imageBuffer.DangerousGetRowSpan(y); + Span rowSpan = pixels.DangerousGetRowSpan(y); Span rowBytes = bgraBytes.Slice(y * widthBytes, widthBytes); - PixelOperations.Instance.ToBgra32Bytes(this.configuration, rowSpan, rowBytes, width); + PixelOperations.Instance.ToBgra32Bytes(this.configuration, rowSpan, rowBytes, pixels.Width); if (!nonOpaque) { Span rowBgra = MemoryMarshal.Cast(rowBytes); diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index e6148a0660..2b74c300a4 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -351,44 +351,53 @@ internal class Vp8Encoder : IDisposable } /// - /// Encodes the image to the specified stream from the . + /// Encodes the animated image frame to the specified stream. /// /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - public void EncodeAnimation(ImageFrame frame, Stream stream) + /// The image frame to encode from. + /// The stream to encode the image data to. + /// The region of interest within the frame to encode. + /// The frame metadata. + public void EncodeAnimation(ImageFrame frame, Stream stream, Rectangle bounds, WebpFrameMetadata frameMetadata) where TPixel : unmanaged, IPixel => - this.Encode(frame, stream, true, null); + this.Encode(stream, frame, bounds, frameMetadata, true, null); /// - /// Encodes the image to the specified stream from the . + /// Encodes the static image frame to the specified stream. /// /// The pixel format. - /// The to encode from. - /// The to encode the image data to. - public void EncodeStatic(Image image, Stream stream) - where TPixel : unmanaged, IPixel => - this.Encode(image.Frames.RootFrame, stream, false, image); + /// The stream to encode the image data to. + /// The image to encode from. + public void EncodeStatic(Stream stream, Image image) + where TPixel : unmanaged, IPixel + { + ImageFrame frame = image.Frames.RootFrame; + this.Encode(stream, frame, image.Bounds, WebpCommonUtils.GetWebpFrameMetadata(frame), false, image); + } /// - /// Encodes the image to the specified stream from the . + /// Encodes the image to the specified stream. /// /// The pixel format. - /// The to encode from. - /// The to encode the image data to. + /// The stream to encode the image data to. + /// The image frame to encode from. + /// The region of interest within the frame to encode. + /// The frame metadata. /// Flag indicating, if an animation parameter is present. - /// The to encode from. - private void Encode(ImageFrame frame, Stream stream, bool hasAnimation, Image image) + /// The image to encode from. + private void Encode(Stream stream, ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, bool hasAnimation, Image image) where TPixel : unmanaged, IPixel { - int width = frame.Width; - int height = frame.Height; + int width = bounds.Width; + int height = bounds.Height; int pixelCount = width * height; Span y = this.Y.GetSpan(); Span u = this.U.GetSpan(); Span v = this.V.GetSpan(); - bool hasAlpha = YuvConversion.ConvertRgbToYuv(frame, this.configuration, this.memoryAllocator, y, u, v); + + Buffer2DRegion pixels = frame.PixelBuffer.GetRegion(bounds); + bool hasAlpha = YuvConversion.ConvertRgbToYuv(pixels, this.configuration, this.memoryAllocator, y, u, v); if (!hasAnimation) { @@ -456,7 +465,7 @@ internal class Vp8Encoder : IDisposable { // TODO: This can potentially run in an separate task. encodedAlphaData = AlphaEncoder.EncodeAlpha( - frame, + pixels, this.configuration, this.memoryAllocator, this.skipMetadata, @@ -477,14 +486,11 @@ internal class Vp8Encoder : IDisposable if (hasAnimation) { - WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(frame); - - // TODO: If we can clip the indexed frame for transparent bounds we can set properties here. prevPosition = new WebpFrameData( - 0, - 0, - (uint)frame.Width, - (uint)frame.Height, + (uint)bounds.X, + (uint)bounds.Y, + (uint)bounds.Width, + (uint)bounds.Height, frameMetadata.FrameDelay, frameMetadata.BlendMethod, frameMetadata.DisposalMethod) diff --git a/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs b/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs index d669a37b74..f8e664ed03 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/YuvConversion.cs @@ -259,7 +259,7 @@ internal static class YuvConversion } /// - /// Converts the RGB values of the image to YUV. + /// Converts the pixel values of the image to YUV. /// /// The pixel type of the image. /// The frame to convert. @@ -269,12 +269,11 @@ internal static class YuvConversion /// Span to store the u component of the image. /// Span to store the v component of the image. /// true, if the image contains alpha data. - public static bool ConvertRgbToYuv(ImageFrame frame, Configuration configuration, MemoryAllocator memoryAllocator, Span y, Span u, Span v) + public static bool ConvertRgbToYuv(Buffer2DRegion frame, Configuration configuration, MemoryAllocator memoryAllocator, Span y, Span u, Span v) where TPixel : unmanaged, IPixel { - Buffer2D imageBuffer = frame.PixelBuffer; - int width = imageBuffer.Width; - int height = imageBuffer.Height; + int width = frame.Width; + int height = frame.Height; int uvWidth = (width + 1) >> 1; // Temporary storage for accumulated R/G/B values during conversion to U/V. @@ -289,8 +288,8 @@ internal static class YuvConversion bool hasAlpha = false; for (rowIndex = 0; rowIndex < height - 1; rowIndex += 2) { - Span rowSpan = imageBuffer.DangerousGetRowSpan(rowIndex); - Span nextRowSpan = imageBuffer.DangerousGetRowSpan(rowIndex + 1); + Span rowSpan = frame.DangerousGetRowSpan(rowIndex); + Span nextRowSpan = frame.DangerousGetRowSpan(rowIndex + 1); PixelOperations.Instance.ToBgra32(configuration, rowSpan, bgraRow0); PixelOperations.Instance.ToBgra32(configuration, nextRowSpan, bgraRow1); @@ -320,7 +319,7 @@ internal static class YuvConversion // Extra last row. if ((height & 1) != 0) { - Span rowSpan = imageBuffer.DangerousGetRowSpan(rowIndex); + Span rowSpan = frame.DangerousGetRowSpan(rowIndex); PixelOperations.Instance.ToBgra32(configuration, rowSpan, bgraRow0); ConvertRgbaToY(bgraRow0, y[(rowIndex * width)..], width); diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index f081cfcd89..d85096c2e8 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -253,7 +253,7 @@ internal class WebpAnimationDecoder : IDisposable private Buffer2D DecodeImageFrameData(WebpFrameData frameData, WebpImageInfo webpInfo) where TPixel : unmanaged, IPixel { - ImageFrame decodedFrame = new(Configuration.Default, (int)frameData.Width, (int)frameData.Height); + ImageFrame decodedFrame = new(this.configuration, (int)frameData.Width, (int)frameData.Height); try { diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 8374870473..7357e097c9 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; @@ -129,6 +130,8 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals if (lossless) { + bool hasAnimation = image.Frames.Count > 1; + using Vp8LEncoder encoder = new( this.memoryAllocator, this.configuration, @@ -141,17 +144,34 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - bool hasAnimation = image.Frames.Count > 1; encoder.EncodeHeader(image, stream, hasAnimation); + + // Encode the first frame. + ImageFrame previousFrame = image.Frames.RootFrame; + WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); + encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); + if (hasAnimation) { - foreach (ImageFrame imageFrame in image.Frames) + WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + + // Encode additional frames + // This frame is reused to store de-duplicated pixel buffers. + using ImageFrame encodingFrame = new(image.Configuration, previousFrame.Size()); + + for (int i = 1; i < image.Frames.Count; i++) { - using Vp8LEncoder enc = new( + ImageFrame currentFrame = image.Frames[i]; + frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); + + ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + + using Vp8LEncoder animatedEncoder = new( this.memoryAllocator, this.configuration, - image.Width, - image.Height, + bounds.Width, + bounds.Height, this.quality, this.skipMetadata, this.method, @@ -159,13 +179,12 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - enc.Encode(imageFrame, stream, true); + animatedEncoder.Encode(encodingFrame, bounds, frameMetadata, stream, hasAnimation); + + previousFrame = currentFrame; + previousDisposal = frameMetadata.DisposalMethod; } } - else - { - encoder.Encode(image.Frames.RootFrame, stream, false); - } encoder.EncodeFooter(image, stream); } @@ -183,17 +202,36 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.filterStrength, this.spatialNoiseShaping, this.alphaCompression); + if (image.Frames.Count > 1) { + // TODO: What about alpha here? encoder.EncodeHeader(image, stream, false, true); - foreach (ImageFrame imageFrame in image.Frames) + // Encode the first frame. + ImageFrame previousFrame = image.Frames.RootFrame; + WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); + WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; + + encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); + + // Encode additional frames + // This frame is reused to store de-duplicated pixel buffers. + using ImageFrame encodingFrame = new(image.Configuration, previousFrame.Size()); + + for (int i = 1; i < image.Frames.Count; i++) { - using Vp8Encoder enc = new( + ImageFrame currentFrame = image.Frames[i]; + frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); + + ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + + using Vp8Encoder animatedEncoder = new( this.memoryAllocator, this.configuration, - image.Width, - image.Height, + bounds.Width, + bounds.Height, this.quality, this.skipMetadata, this.method, @@ -202,12 +240,15 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.spatialNoiseShaping, this.alphaCompression); - enc.EncodeAnimation(imageFrame, stream); + animatedEncoder.EncodeAnimation(encodingFrame, stream, bounds, frameMetadata); + + previousFrame = currentFrame; + previousDisposal = frameMetadata.DisposalMethod; } } else { - encoder.EncodeStatic(image, stream); + encoder.EncodeStatic(stream, image); } encoder.EncodeFooter(image, stream); diff --git a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs index 433b280bc3..3ae6601b18 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/YuvConversionTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; @@ -143,7 +142,7 @@ public class YuvConversionTests }; // act - YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, config, memoryAllocator, y, u, v); + YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame.PixelBuffer.GetRegion(), config, memoryAllocator, y, u, v); // assert Assert.True(expectedY.AsSpan().SequenceEqual(y)); @@ -249,7 +248,7 @@ public class YuvConversionTests }; // act - YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame, config, memoryAllocator, y, u, v); + YuvConversion.ConvertRgbToYuv(image.Frames.RootFrame.PixelBuffer.GetRegion(), config, memoryAllocator, y, u, v); // assert Assert.True(expectedY.AsSpan().SequenceEqual(y)); From 4b852e6528e76a8746a7b51d8d12dcd654afcb85 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Nov 2023 21:58:10 +1000 Subject: [PATCH 049/219] Update tests, fix issues --- src/ImageSharp/Formats/AnimationUtilities.cs | 50 +++++++++++++++---- .../Formats/Gif/MetadataExtensions.cs | 2 +- .../Formats/Png/Chunks/PngPhysical.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 31 +++++++++--- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 14 +++++- src/ImageSharp/Formats/Png/PngMetadata.cs | 2 +- .../Formats/Webp/Chunks/WebpFrameData.cs | 14 +++--- .../Formats/Webp/MetadataExtensions.cs | 2 +- .../Formats/Webp/WebpAnimationDecoder.cs | 2 +- ...bpBlendingMethod.cs => WebpBlendMethod.cs} | 4 +- .../Formats/Webp/WebpCommonUtils.cs | 4 +- .../Formats/Webp/WebpEncoderCore.cs | 25 +++++++++- .../Formats/Webp/WebpFrameMetadata.cs | 4 +- .../Formats/GeneralFormatTests.cs | 14 +++--- .../Formats/Gif/GifEncoderTests.cs | 9 ++-- .../Formats/Png/PngEncoderTests.cs | 11 ++-- .../Formats/WebP/WebpEncoderTests.cs | 10 ++-- .../TestUtilities/ImagingTestCaseUtility.cs | 4 +- ...de_8BitColor_WithOctreeQuantizer_rgb32.bmp | 2 +- ...Encode_8BitColor_WithWuQuantizer_rgb32.bmp | 2 +- ...onFilterInBox_Rgba32_CalliphoraPartial.png | 4 +- ...erFilterInBox_Rgba32_CalliphoraPartial.png | 4 +- ...DependOnSinglePixelType_Bgra32_filter0.png | 4 +- ...tDependOnSinglePixelType_Rgb24_filter0.png | 4 +- ...DependOnSinglePixelType_Rgba32_filter0.png | 4 +- ...ndOnSinglePixelType_RgbaVector_filter0.png | 4 +- ...rksWithAllErrorDiffusers_Bike_Atkinson.png | 4 +- ..._WorksWithAllErrorDiffusers_Bike_Burks.png | 4 +- ...hAllErrorDiffusers_Bike_FloydSteinberg.png | 4 +- ...lErrorDiffusers_Bike_JarvisJudiceNinke.png | 4 +- ...orksWithAllErrorDiffusers_Bike_Sierra2.png | 4 +- ...orksWithAllErrorDiffusers_Bike_Sierra3.png | 4 +- ...sWithAllErrorDiffusers_Bike_SierraLite.png | 4 +- ...thAllErrorDiffusers_Bike_StevensonArce.png | 4 +- ...WorksWithAllErrorDiffusers_Bike_Stucki.png | 4 +- ...orDiffusers_CalliphoraPartial_Atkinson.png | 4 +- ...ErrorDiffusers_CalliphoraPartial_Burks.png | 4 +- ...users_CalliphoraPartial_FloydSteinberg.png | 4 +- ...rs_CalliphoraPartial_JarvisJudiceNinke.png | 4 +- ...rorDiffusers_CalliphoraPartial_Sierra2.png | 4 +- ...rorDiffusers_CalliphoraPartial_Sierra3.png | 4 +- ...Diffusers_CalliphoraPartial_SierraLite.png | 4 +- ...fusers_CalliphoraPartial_StevensonArce.png | 4 +- ...rrorDiffusers_CalliphoraPartial_Stucki.png | 4 +- ...DependOnSinglePixelType_Bgra32_filter0.png | 4 +- ...tDependOnSinglePixelType_Rgb24_filter0.png | 4 +- ...DependOnSinglePixelType_Rgba32_filter0.png | 4 +- ...ndOnSinglePixelType_RgbaVector_filter0.png | 4 +- ..._WorksWithAllDitherers_Bike_Bayer16x16.png | 4 +- ...er_WorksWithAllDitherers_Bike_Bayer2x2.png | 4 +- ...er_WorksWithAllDitherers_Bike_Bayer4x4.png | 4 +- ...er_WorksWithAllDitherers_Bike_Bayer8x8.png | 4 +- ..._WorksWithAllDitherers_Bike_Ordered3x3.png | 4 +- ...Ditherers_CalliphoraPartial_Bayer16x16.png | 4 +- ...llDitherers_CalliphoraPartial_Bayer2x2.png | 4 +- ...llDitherers_CalliphoraPartial_Bayer4x4.png | 4 +- ...llDitherers_CalliphoraPartial_Bayer8x8.png | 4 +- ...Ditherers_CalliphoraPartial_Ordered3x3.png | 4 +- ...zed_Encode_Artifacts_Rgba32_issue_2469.png | 4 +- ...InBox_Bike_OctreeQuantizer_ErrorDither.png | 4 +- ...ionInBox_Bike_OctreeQuantizer_NoDither.png | 4 +- ...Box_Bike_OctreeQuantizer_OrderedDither.png | 4 +- ...ke_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ..._Bike_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ike_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...x_Bike_WernerPaletteQuantizer_NoDither.png | 4 +- ...e_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...tionInBox_Bike_WuQuantizer_ErrorDither.png | 4 +- ...izationInBox_Bike_WuQuantizer_NoDither.png | 4 +- ...onInBox_Bike_WuQuantizer_OrderedDither.png | 4 +- ...oraPartial_OctreeQuantizer_ErrorDither.png | 4 +- ...iphoraPartial_OctreeQuantizer_NoDither.png | 4 +- ...aPartial_OctreeQuantizer_OrderedDither.png | 4 +- ...al_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ...rtial_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ial_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...artial_WernerPaletteQuantizer_NoDither.png | 4 +- ...l_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...liphoraPartial_WuQuantizer_ErrorDither.png | 4 +- ...CalliphoraPartial_WuQuantizer_NoDither.png | 4 +- ...phoraPartial_WuQuantizer_OrderedDither.png | 4 +- ...david_OctreeQuantizer_ErrorDither_0.25.png | 4 +- ..._david_OctreeQuantizer_ErrorDither_0.5.png | 4 +- ...david_OctreeQuantizer_ErrorDither_0.75.png | 4 +- ...le_david_OctreeQuantizer_ErrorDither_0.png | 4 +- ...le_david_OctreeQuantizer_ErrorDither_1.png | 4 +- ...vid_OctreeQuantizer_OrderedDither_0.25.png | 4 +- ...avid_OctreeQuantizer_OrderedDither_0.5.png | 4 +- ...vid_OctreeQuantizer_OrderedDither_0.75.png | 4 +- ..._david_OctreeQuantizer_OrderedDither_0.png | 4 +- ..._david_OctreeQuantizer_OrderedDither_1.png | 4 +- ...bSafePaletteQuantizer_ErrorDither_0.25.png | 4 +- ...ebSafePaletteQuantizer_ErrorDither_0.5.png | 4 +- ...bSafePaletteQuantizer_ErrorDither_0.75.png | 4 +- ..._WebSafePaletteQuantizer_ErrorDither_0.png | 4 +- ..._WebSafePaletteQuantizer_ErrorDither_1.png | 4 +- ...afePaletteQuantizer_OrderedDither_0.25.png | 4 +- ...SafePaletteQuantizer_OrderedDither_0.5.png | 4 +- ...afePaletteQuantizer_OrderedDither_0.75.png | 4 +- ...ebSafePaletteQuantizer_OrderedDither_0.png | 4 +- ...ebSafePaletteQuantizer_OrderedDither_1.png | 4 +- ...ernerPaletteQuantizer_ErrorDither_0.25.png | 4 +- ...WernerPaletteQuantizer_ErrorDither_0.5.png | 4 +- ...ernerPaletteQuantizer_ErrorDither_0.75.png | 4 +- ...d_WernerPaletteQuantizer_ErrorDither_0.png | 4 +- ...d_WernerPaletteQuantizer_ErrorDither_1.png | 4 +- ...nerPaletteQuantizer_OrderedDither_0.25.png | 4 +- ...rnerPaletteQuantizer_OrderedDither_0.5.png | 4 +- ...nerPaletteQuantizer_OrderedDither_0.75.png | 4 +- ...WernerPaletteQuantizer_OrderedDither_0.png | 4 +- ...WernerPaletteQuantizer_OrderedDither_1.png | 4 +- ...ale_david_WuQuantizer_ErrorDither_0.25.png | 4 +- ...cale_david_WuQuantizer_ErrorDither_0.5.png | 4 +- ...ale_david_WuQuantizer_ErrorDither_0.75.png | 4 +- ...gScale_david_WuQuantizer_ErrorDither_0.png | 4 +- ...gScale_david_WuQuantizer_ErrorDither_1.png | 4 +- ...e_david_WuQuantizer_OrderedDither_0.25.png | 4 +- ...le_david_WuQuantizer_OrderedDither_0.5.png | 4 +- ...e_david_WuQuantizer_OrderedDither_0.75.png | 4 +- ...cale_david_WuQuantizer_OrderedDither_0.png | 4 +- ...cale_david_WuQuantizer_OrderedDither_1.png | 4 +- ...ation_Bike_OctreeQuantizer_ErrorDither.png | 4 +- ...tization_Bike_OctreeQuantizer_NoDither.png | 4 +- ...ion_Bike_OctreeQuantizer_OrderedDither.png | 4 +- ...ke_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ..._Bike_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ike_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...n_Bike_WernerPaletteQuantizer_NoDither.png | 4 +- ...e_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...ntization_Bike_WuQuantizer_ErrorDither.png | 4 +- ...Quantization_Bike_WuQuantizer_NoDither.png | 4 +- ...ization_Bike_WuQuantizer_OrderedDither.png | 4 +- ...oraPartial_OctreeQuantizer_ErrorDither.png | 4 +- ...iphoraPartial_OctreeQuantizer_NoDither.png | 4 +- ...aPartial_OctreeQuantizer_OrderedDither.png | 4 +- ...al_WebSafePaletteQuantizer_ErrorDither.png | 4 +- ...rtial_WebSafePaletteQuantizer_NoDither.png | 4 +- ..._WebSafePaletteQuantizer_OrderedDither.png | 4 +- ...ial_WernerPaletteQuantizer_ErrorDither.png | 4 +- ...artial_WernerPaletteQuantizer_NoDither.png | 4 +- ...l_WernerPaletteQuantizer_OrderedDither.png | 4 +- ...liphoraPartial_WuQuantizer_ErrorDither.png | 4 +- ...CalliphoraPartial_WuQuantizer_NoDither.png | 4 +- ...phoraPartial_WuQuantizer_OrderedDither.png | 4 +- 147 files changed, 398 insertions(+), 318 deletions(-) rename src/ImageSharp/Formats/Webp/{WebpBlendingMethod.cs => WebpBlendMethod.cs} (92%) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index ee9a85ac43..b66efd7f56 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -27,15 +27,19 @@ internal static class AnimationUtilities /// The current frame. /// The resultant output. /// The value to use when replacing duplicate pixels. + /// The clamping bound to apply when calculating difference bounds. /// The representing the operation result. public static (bool Difference, Rectangle Bounds) DeDuplicatePixels( Configuration configuration, ImageFrame? previousFrame, ImageFrame currentFrame, ImageFrame resultFrame, - Vector4 replacement) + Vector4 replacement, + ClampingMode clampingMode = ClampingMode.None) where TPixel : unmanaged, IPixel { + // TODO: This would be faster (but more complicated to find diff bounds) if we operated on Rgba32. + // If someone wants to do that, they have my unlimited thanks. MemoryAllocator memoryAllocator = configuration.MemoryAllocator; IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 3, AllocationOptions.Clean); Span previous = buffers.GetSpan()[..currentFrame.Width]; @@ -78,10 +82,11 @@ internal static class AnimationUtilities Vector256 c = Unsafe.Add(ref currentBase, x); // Compare the previous and current pixels - Vector256 neq = Avx.CompareEqual(p, c); - Vector256 mask = neq.AsInt32(); + Vector256 mask = Avx2.CompareEqual(p.AsInt32(), c.AsInt32()); + mask = Avx2.CompareEqual(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); + mask = Avx2.And(mask, Avx2.Shuffle(mask, 0b_01_00_11_10)).AsInt32(); - neq = Avx.Xor(neq, Vector256.AllBitsSet); + Vector256 neq = Avx2.Xor(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); int m = Avx2.MoveMask(neq.AsByte()); if (m != 0) { @@ -95,11 +100,7 @@ internal static class AnimationUtilities hasDiff = true; } - // Capture the original alpha values. - mask = Avx2.HorizontalAdd(mask, mask); - mask = Avx2.HorizontalAdd(mask, mask); - mask = Avx2.CompareEqual(mask, Vector256.Create(-4)); - + // Replace the pixel value with the replacement if the full pixel is matched. Vector256 r = Avx.BlendVariable(c, replacement256, mask.AsSingle()); Unsafe.Add(ref resultBase, x) = r; @@ -153,6 +154,37 @@ internal static class AnimationUtilities Numerics.Clamp(right, left + 1, resultFrame.Width), Numerics.Clamp(bottom, top + 1, resultFrame.Height)); + // Webp requires even bounds + if (clampingMode == ClampingMode.Even) + { + bounds.Width = Math.Min(resultFrame.Width, bounds.Width + (bounds.X & 1)); + bounds.Height = Math.Min(resultFrame.Height, bounds.Height + (bounds.Y & 1)); + bounds.X = Math.Max(0, bounds.X - (bounds.X & 1)); + bounds.Y = Math.Max(0, bounds.Y - (bounds.Y & 1)); + } + return new(hasDiff, bounds); } + + public static void CopySource(ImageFrame source, ImageFrame destination, Rectangle bounds) + where TPixel : unmanaged, IPixel + { + Buffer2DRegion sourceBuffer = source.PixelBuffer.GetRegion(bounds); + Buffer2DRegion destBuffer = destination.PixelBuffer.GetRegion(bounds); + for (int y = 0; y < destination.Height; y++) + { + Span sourceRow = sourceBuffer.DangerousGetRowSpan(y); + Span destRow = destBuffer.DangerousGetRowSpan(y); + sourceRow.CopyTo(destRow); + } + } +} + +#pragma warning disable SA1201 // Elements should appear in the correct order +internal enum ClampingMode +#pragma warning restore SA1201 // Elements should appear in the correct order +{ + None, + + Even, } diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 1b9b6ac58c..16f788e3db 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -83,7 +83,7 @@ public static partial class MetadataExtensions ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), DisposalMode = GetMode(source.DisposalMethod), - BlendMode = FrameBlendMode.Over, + BlendMode = source.DisposalMethod == GifDisposalMethod.RestoreToBackground ? FrameBlendMode.Source : FrameBlendMode.Over, }; private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch diff --git a/src/ImageSharp/Formats/Png/Chunks/PngPhysical.cs b/src/ImageSharp/Formats/Png/Chunks/PngPhysical.cs index 7847882484..8af0ac8ca7 100644 --- a/src/ImageSharp/Formats/Png/Chunks/PngPhysical.cs +++ b/src/ImageSharp/Formats/Png/Chunks/PngPhysical.cs @@ -61,10 +61,10 @@ internal readonly struct PngPhysical /// The constructed PngPhysicalChunkData instance. public static PngPhysical FromMetadata(ImageMetadata meta) { - byte unitSpecifier = 0; uint x; uint y; + byte unitSpecifier; switch (meta.ResolutionUnits) { case PixelResolutionUnit.AspectRatio: diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index b0706b14c7..cb4f599eb8 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -217,7 +217,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals chunk.Length - 4, currentFrame, pngMetadata, - this.ReadNextDataChunkAndSkipSeq, + this.ReadNextFrameDataChunk, currentFrameControl.Value, cancellationToken); @@ -1719,19 +1719,34 @@ internal sealed class PngDecoderCore : IImageDecoderInternals } /// - /// Reads the next data chunk and skip sequence number. + /// Reads the next animated frame data chunk. /// /// Count of bytes in the next data chunk, or 0 if there are no more data chunks left. - private int ReadNextDataChunkAndSkipSeq() + private int ReadNextFrameDataChunk() { - int length = this.ReadNextDataChunk(); - if (this.ReadNextDataChunk() is 0) + if (this.nextChunk != null) { - return length; + return 0; } - this.currentStream.Position += 4; // Skip sequence number - return length - 4; + Span buffer = stackalloc byte[20]; + + _ = this.currentStream.Read(buffer, 0, 4); + + if (this.TryReadChunk(buffer, out PngChunk chunk)) + { + if (chunk.Type is PngChunkType.FrameData) + { + chunk.Data?.Dispose(); + + this.currentStream.Position += 4; // Skip sequence number + return chunk.Length - 4; + } + + this.nextChunk = chunk; + } + + return 0; } /// diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 016c422337..7908109e8e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -214,6 +214,16 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + if (difference && previousDisposal != PngDisposalMethod.RestoreToBackground) + { + if (frameMetadata.BlendMethod == PngBlendMethod.Source) + { + // We've potentially introduced transparency within our area of interest + // so we need to overwrite the changed area with the full data. + AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); + } + } + if (clearTransparency) { ClearTransparentPixels(encodingFrame); @@ -258,7 +268,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) { - return png; + return (PngMetadata)png.DeepClone(); } if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) @@ -282,7 +292,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) { - return png; + return (PngFrameMetadata)png.DeepClone(); } if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 7f4052846a..128237684c 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -100,7 +100,7 @@ public class PngMetadata : IDeepCloneable if (c == metadata.BackgroundColor) { // Png treats background as fully empty - c = default; + c = Color.Transparent; break; } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index c8c4a74a00..5ed7aab1ea 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -12,7 +12,7 @@ internal readonly struct WebpFrameData /// public const uint HeaderSize = 16; - public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, WebpBlendingMethod blendingMethod, WebpDisposalMethod disposalMethod) + public WebpFrameData(uint dataSize, uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod) { this.DataSize = dataSize; this.X = x; @@ -32,12 +32,12 @@ internal readonly struct WebpFrameData width, height, duration, - (flags & 2) == 0 ? WebpBlendingMethod.Over : WebpBlendingMethod.Source, + (flags & 2) == 0 ? WebpBlendMethod.Over : WebpBlendMethod.Source, (flags & 1) == 1 ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose) { } - public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, WebpBlendingMethod blendingMethod, WebpDisposalMethod disposalMethod) + public WebpFrameData(uint x, uint y, uint width, uint height, uint duration, WebpBlendMethod blendingMethod, WebpDisposalMethod disposalMethod) : this(0, x, y, width, height, duration, blendingMethod, disposalMethod) { } @@ -76,7 +76,7 @@ internal readonly struct WebpFrameData /// /// Gets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// - public WebpBlendingMethod BlendingMethod { get; } + public WebpBlendMethod BlendingMethod { get; } /// /// Gets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. @@ -93,7 +93,7 @@ internal readonly struct WebpFrameData { byte flags = 0; - if (this.BlendingMethod is WebpBlendingMethod.Source) + if (this.BlendingMethod is WebpBlendMethod.Source) { // Set blending flag. flags |= 2; @@ -107,8 +107,8 @@ internal readonly struct WebpFrameData long pos = RiffHelper.BeginWriteChunk(stream, (uint)WebpChunkType.FrameData); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.X / 2); - WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Y / 2); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, (uint)Math.Round(this.X / 2f)); + WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, (uint)Math.Round(this.Y / 2f)); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Width - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Height - 1); WebpChunkParsingUtils.WriteUInt24LittleEndian(stream, this.Duration); diff --git a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs index 10c72a3d9c..731d3f1ff2 100644 --- a/src/ImageSharp/Formats/Webp/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Webp/MetadataExtensions.cs @@ -63,7 +63,7 @@ public static partial class MetadataExtensions ColorTableMode = FrameColorTableMode.Global, Duration = TimeSpan.FromMilliseconds(source.FrameDelay), DisposalMode = GetMode(source.DisposalMethod), - BlendMode = source.BlendMethod == WebpBlendingMethod.Over ? FrameBlendMode.Over : FrameBlendMode.Source, + BlendMode = source.BlendMethod == WebpBlendMethod.Over ? FrameBlendMode.Over : FrameBlendMode.Source, }; private static FrameDisposalMode GetMode(WebpDisposalMethod method) => method switch diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index d85096c2e8..65f1a4da46 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -202,7 +202,7 @@ internal class WebpAnimationDecoder : IDisposable using Buffer2D decodedImageFrame = this.DecodeImageFrameData(frameData, webpInfo); - bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendingMethod.Over; + bool blend = previousFrame != null && frameData.BlendingMethod == WebpBlendMethod.Over; DrawDecodedImageFrameOnCanvas(decodedImageFrame, imageFrame, regionRectangle, blend); previousFrame = currentFrame ?? image.Frames.RootFrame; diff --git a/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs b/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs similarity index 92% rename from src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs rename to src/ImageSharp/Formats/Webp/WebpBlendMethod.cs index 482d62cd23..f16f7650c7 100644 --- a/src/ImageSharp/Formats/Webp/WebpBlendingMethod.cs +++ b/src/ImageSharp/Formats/Webp/WebpBlendMethod.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats.Webp; @@ -6,7 +6,7 @@ namespace SixLabors.ImageSharp.Formats.Webp; /// /// Indicates how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// -public enum WebpBlendingMethod +public enum WebpBlendMethod { /// /// Do not blend. After disposing of the previous frame, diff --git a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs index bb7dd6f279..49482260bb 100644 --- a/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpCommonUtils.cs @@ -20,7 +20,7 @@ internal static class WebpCommonUtils { if (image.Metadata.TryGetWebpMetadata(out WebpMetadata? webp)) { - return webp; + return (WebpMetadata)webp.DeepClone(); } if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) @@ -44,7 +44,7 @@ internal static class WebpCommonUtils { if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) { - return webp; + return (WebpFrameMetadata)webp.DeepClone(); } if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index 7357e097c9..db12d7c676 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -165,7 +165,18 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero, ClampingMode.Even); + + if (difference && previousDisposal != WebpDisposalMethod.RestoreToBackground) + { + if (frameMetadata.BlendMethod == WebpBlendMethod.Source) + { + // We've potentially introduced transparency within our area of interest + // so we need to overwrite the changed area with the full data. + AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); + } + } using Vp8LEncoder animatedEncoder = new( this.memoryAllocator, @@ -225,7 +236,17 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero, ClampingMode.Even); + + if (difference && previousDisposal != WebpDisposalMethod.RestoreToBackground) + { + if (frameMetadata.BlendMethod == WebpBlendMethod.Source) + { + // We've potentially introduced transparency within our area of interest + // so we need to overwrite the changed area with the full data. + AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); + } + } using Vp8Encoder animatedEncoder = new( this.memoryAllocator, diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index 667b8f8f46..422ad6bc7c 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -29,7 +29,7 @@ public class WebpFrameMetadata : IDeepCloneable /// /// Gets or sets how transparent pixels of the current frame are to be blended with corresponding pixels of the previous canvas. /// - public WebpBlendingMethod BlendMethod { get; set; } + public WebpBlendMethod BlendMethod { get; set; } /// /// Gets or sets how the current frame is to be treated after it has been displayed (before rendering the next frame) on the canvas. @@ -49,7 +49,7 @@ public class WebpFrameMetadata : IDeepCloneable => new() { FrameDelay = (uint)metadata.Duration.Milliseconds, - BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendingMethod.Source : WebpBlendingMethod.Over, + BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendMethod.Source : WebpBlendMethod.Over, DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose }; } diff --git a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs index 1d84d6600a..27511f7beb 100644 --- a/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs +++ b/tests/ImageSharp.Tests/Formats/GeneralFormatTests.cs @@ -162,37 +162,37 @@ public class GeneralFormatTests foreach (TestFile file in Files) { using Image image = file.CreateRgba32Image(); - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.bmp"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.bmp"))) { image.SaveAsBmp(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.jpg"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.jpg"))) { image.SaveAsJpeg(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.pbm"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.pbm"))) { image.SaveAsPbm(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.png"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.png"))) { image.SaveAsPng(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.gif"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.gif"))) { image.SaveAsGif(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.tga"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.tga"))) { image.SaveAsTga(output); } - using (FileStream output = File.OpenWrite(Path.Combine(path, $"{file.FileNameWithoutExtension}.tiff"))) + using (FileStream output = File.Create(Path.Combine(path, $"{file.FileNameWithoutExtension}.tiff"))) { image.SaveAsTiff(output); } diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index ef04a4fbaf..d6d63baabf 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -360,15 +360,16 @@ public class GifEncoderTests public static string[] Animated => TestImages.Gif.Animated; - [Theory]//(Skip = "Enable for visual animated testing")] + [Theory(Skip = "Enable for visual animated testing")] [WithFileCollection(nameof(Animated), PixelTypes.Rgba32)] public void Encode_Animated_VisualTest(TestImageProvider provider) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(); - //image.DebugSaveMultiFrame(provider); - - provider.Utility.SaveTestOutputFile(image, "gif", new GifEncoder() { ColorTableMode = GifColorTableMode.Local}, "animated"); + provider.Utility.SaveTestOutputFile(image, "webp", new WebpEncoder() { FileFormat = WebpFileFormatType.Lossless }, "animated"); + provider.Utility.SaveTestOutputFile(image, "webp", new WebpEncoder() { FileFormat = WebpFileFormatType.Lossy }, "animated-lossy"); + provider.Utility.SaveTestOutputFile(image, "png", new PngEncoder(), "animated"); + provider.Utility.SaveTestOutputFile(image, "gif", new GifEncoder(), "animated"); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 45dd30b3b0..f8fc774b78 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -479,19 +479,16 @@ public partial class PngEncoderTests } [Theory] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.Leo, PixelTypes.Rgba32)] public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(GifDecoder.Instance); - using MemoryStream memStream = new(); + using MemoryStream memStream = new(); image.Save(memStream, PngEncoder); memStream.Position = 0; - image.Save(provider.Utility.GetTestOutputFileName("png"), new PngEncoder()); - image.Save(provider.Utility.GetTestOutputFileName("gif"), new GifEncoder()); - using Image output = Image.Load(memStream); // TODO: Find a better way to compare. @@ -556,10 +553,10 @@ public partial class PngEncoderTests switch (webpF.BlendMethod) { - case WebpBlendingMethod.Source: + case WebpBlendMethod.Source: Assert.Equal(PngBlendMethod.Source, pngF.BlendMethod); break; - case WebpBlendingMethod.Over: + case WebpBlendMethod.Over: default: Assert.Equal(PngBlendMethod.Over, pngF.BlendMethod); break; diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 0fafdbe161..6baacb38ce 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -63,7 +63,7 @@ public class WebpEncoderTests } [Theory] - [WithFile(TestImages.Gif.Giphy, PixelTypes.Rgba32)] + [WithFile(TestImages.Gif.Leo, PixelTypes.Rgba32)] public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -115,6 +115,10 @@ public class WebpEncoderTests image.Save(memStream, new WebpEncoder()); memStream.Position = 0; + provider.Utility.SaveTestOutputFile(image, "gif", new GifEncoder()); + provider.Utility.SaveTestOutputFile(image, "png", new PngEncoder()); + provider.Utility.SaveTestOutputFile(image, "webp", new WebpEncoder()); + using Image output = Image.Load(memStream); ImageComparer.Exact.VerifySimilarity(output, image); PngMetadata png = image.Metadata.GetPngMetadata(); @@ -132,11 +136,11 @@ public class WebpEncoderTests switch (pngF.BlendMethod) { case PngBlendMethod.Source: - Assert.Equal(WebpBlendingMethod.Source, webpF.BlendMethod); + Assert.Equal(WebpBlendMethod.Source, webpF.BlendMethod); break; case PngBlendMethod.Over: default: - Assert.Equal(WebpBlendingMethod.Over, webpF.BlendMethod); + Assert.Equal(WebpBlendMethod.Over, webpF.BlendMethod); break; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 9b100047f0..2243c852d2 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -171,7 +171,7 @@ public class ImagingTestCaseUtility encoder ??= TestEnvironment.GetReferenceEncoder(path); - using (FileStream stream = File.OpenWrite(path)) + using (FileStream stream = File.Create(path)) { image.Save(stream, encoder); } @@ -227,7 +227,7 @@ public class ImagingTestCaseUtility { using Image frameImage = image.Frames.CloneFrame(file.Index); string filePath = file.FileName; - using FileStream stream = File.OpenWrite(filePath); + using FileStream stream = File.Create(filePath); frameImage.Save(stream, encoder); } diff --git a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp index 2b8e05b070..d484eace0f 100644 --- a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp +++ b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11375b15df083d98335f4a4baf0717e7fdd6b21ab2132a6815cadc787ac17e7d +oid sha256:23a9d9233314ec08bd3e464f245e69d96566cbb12d2dba36c69bba483d6ba6b8 size 9270 diff --git a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp index f7eb06c558..6896c4fa6a 100644 --- a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp +++ b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e063e97cd8a000de6830adcc3961a7dc41785d40cd4d83af10ca38d96e071362 +oid sha256:3052831cb18fecc26f54e29dfe19b538d2e0d3c104ddd7ec5bc8e0adcf56693c size 9270 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png index dd2f49f08b..39bb7e52b9 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cafc426ac8e8d02a87f67c90e8c1976c5fae0e12b49deae52ad08476f7ed49a4 -size 266391 +oid sha256:e89597ab9aa006d026a560d1482350739bd93604d9c6726f6730d782c017a0a3 +size 273049 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png index f226b166e4..133112867c 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98115a7087aced0c28cefa32a57bc72be245886cabeefc4ff7faf7984236218c -size 271226 +oid sha256:59d331efd9e6d926eaf90bed1f76b3ba55b2a42d2f83fc512a985cdea97781ec +size 271152 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png index daa4b5e437..cac3b9c421 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0369747820c86bb692fc7b75f3519095c9b2a58a885ebd37c871c103d08405a0 -size 720 +oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 +size 727 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png index daa4b5e437..cac3b9c421 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0369747820c86bb692fc7b75f3519095c9b2a58a885ebd37c871c103d08405a0 -size 720 +oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 +size 727 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png index daa4b5e437..cac3b9c421 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0369747820c86bb692fc7b75f3519095c9b2a58a885ebd37c871c103d08405a0 -size 720 +oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 +size 727 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png index d8f9b640dd..4a3a1e874b 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f63aebed17504ef50d96ac7e58dc41f5227a83a38810359ed8e9cecda137183b -size 720 +oid sha256:2f6df6c76c0f3795c439147fd49d658e52fae5c24a071ee0f4fed7aa096d87d1 +size 719 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png index 3656e32db6..5db7bd5ef3 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:471eaf2e532b40592c86dc816709d3ae4bbd64892006e00fd611ef6869d3b934 -size 52070 +oid sha256:c419d6b6cb589f95bff06514e3a5da37d7b5704aa3f9e6f4365fe5e00c6d81d1 +size 50670 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png index 7cafd50c17..b2c8578011 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:91fb9966a4b3eaefd5533ddf0b98ec08fbf8cbc263e4ebd438895e6d4129dd03 -size 61447 +oid sha256:90c337c38076fb597ecde87e0e8b5b95c369a90a99e64c5add3b31fc778cb52d +size 61178 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png index 5d0c82e058..7ceb6114ad 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d74faa8d188a2915739de64ba9d71b2132b53c8d154db22510c524ae757578a5 -size 61183 +oid sha256:7ce4b978b800820275635ae8da59212661c74a1b6ba9050ebf052c87315aedef +size 62107 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png index 584e677e20..9f2a2482aa 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:080cc89d1d6568a2c9b707bf05428ab5febd2951e37223f96e349cc6646d32aa -size 56070 +oid sha256:e44a87274d4f4fc5f1a0a849f27108ff8b98410f5d1e5e328236a9c79b9af51b +size 56175 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png index 641ecaca19..a8a0eda5e1 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c7589986c1a762d52fe8ffc252e9938ff0e3a9e00b91ea7f5e36d4335b2b7870 -size 58502 +oid sha256:542285d1c2a375f64680173ca2736399d061009413e8aacf62f785425357f868 +size 58538 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png index 61bbf2b155..58a5909c06 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:934042746c3a9b652069da26b479e2be7cbdb17ab20e41c5e271013a76e96e46 -size 58480 +oid sha256:b4aa18018421bda728ec9adab4eff235d4f4c683a0bb5328dab386833685ab35 +size 57616 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png index 42e595b0ab..847aab49cd 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:03d5d5cbf1b2c0be736aa2bf726ad4bb04fca77aff393edb9663a7915a794264 -size 62418 +oid sha256:ec9d5fe07a99a995e889870ac4f6d264360adf1dbc5cb656d5657e096fe7f393 +size 61838 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png index 5cd6eca10d..d8cb185c9e 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:19a0d8667bfd01e18adbfca778e868ea7a6c43d427f9ae40eb4281d438ef509c -size 54464 +oid sha256:b2dd1df6e5fb97b5fdeab6450713432ee1e0a318953b11ab25f4618bde369792 +size 54658 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png index 5a97796404..6df5a227bf 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11c1056e013292e0543598f5690625b9bac0420a15fd1f37f6484daa3b8326fa -size 60074 +oid sha256:ba66ef358ebcec36932e6d2874827846b31585fcbc0683e26c548fc3706e27e3 +size 57294 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png index d0c3196426..c4a20b45a3 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3fcf9b7e4ee34e80e8811f94940aff09a5392c21019fc86b145d16fd9c6b1cd2 -size 57501 +oid sha256:9f777e6d61a882da066a00b9d268be5fdbf49bdbccb568eb5bb3d959fe9f4fb0 +size 57454 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png index 773ff203ac..0c52494844 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f0d9a43d8a47e00f6e5932b57f99565370a7239496fdbe162fb774497c4ef2a -size 59377 +oid sha256:2b00d60902d54f911a9b4ab9be225ab589073b9f0efe06019895a75e487eadec +size 59415 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png index a41b9989f8..0364487787 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d4a64da29f144d4d4c525ea45e56819e02a46030ae09542be01fdd8ffc85a295 -size 60377 +oid sha256:ded9cb4986e620f5fc11486ccdf81934dff7b3cea7db7e292929d339ecc21714 +size 60116 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png index 39fc93541e..587929f1fa 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90fc8048141b2182e4851a48ac5a79c96210eab9e56468fe06f90e7e70a7c180 -size 58539 +oid sha256:1518a2c1840a8d88767a45c7ba08b904ea471c7422fbb5f2b623f1f219992f83 +size 58479 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png index e7bd1c6f36..0cccb2c775 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b312bd18eba03a37121bbcfb3b285f97fe22283b51256883ce0235bb8605b757 -size 58616 +oid sha256:01c6000407f5302a5dd27a88053f795cdb101c791f92e983e6859792ef8a0935 +size 58879 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png index f3155ba80b..7150bcc1f0 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:750ccd26984a4d5a370c1af6ca5dd1c9c5c6c66e693f7645130fd1669e3b7b4e -size 58923 +oid sha256:11438d8eef23ae6ff5b7d37f0ccc9b6bfe744abb2dc95785a5769c306e51d11b +size 58908 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png index d5cbbd3e04..d1919cbd1d 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f9d3777a936883a2177a964f24d9ac86c8a106c375583bc9a8fbeb0ec39a7dc6 -size 60610 +oid sha256:57584582f914c0c059899f9241de006526a14081093b647972c363b00de62a57 +size 60492 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png index 5b83ace203..6778314d56 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f638821c29d852d6fabe4cc4cfe802e386024835ad07ee496a7bec7a930e851b -size 57886 +oid sha256:adfc7192b03c29addbc9c19e9eefc5c122d35d3d0fae7dfa65d3390ee5f60502 +size 57887 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png index 46dace67b2..5c8c2f3cc5 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c6e86bfc1594ec4cb8f89a1c92a42778c59aa755ce170a97afb8cab3e623aa79 -size 58376 +oid sha256:9735370ed168043d1fd176a258f08fcd705dcefc1d5e6841d012e843ec34d7a9 +size 58485 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png index 909af9b6d3..e2e4147f68 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e849620a297e29ba11014c54430db01d851e4192650f6e39e0410591244cb5 -size 865 +oid sha256:a3253003b088c9975725cf321c2fc827547a5feb199f2d1aa515c69bde59deb7 +size 871 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png index 909af9b6d3..aa0e9a4824 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e849620a297e29ba11014c54430db01d851e4192650f6e39e0410591244cb5 -size 865 +oid sha256:bb3e3b9b3001e76505fb0e2db7ad200cad2a016c06f1993c60c3cab42c134863 +size 867 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png index 909af9b6d3..e2e4147f68 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e849620a297e29ba11014c54430db01d851e4192650f6e39e0410591244cb5 -size 865 +oid sha256:a3253003b088c9975725cf321c2fc827547a5feb199f2d1aa515c69bde59deb7 +size 871 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png index 909af9b6d3..e2e4147f68 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f7e849620a297e29ba11014c54430db01d851e4192650f6e39e0410591244cb5 -size 865 +oid sha256:a3253003b088c9975725cf321c2fc827547a5feb199f2d1aa515c69bde59deb7 +size 871 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png index 5961b0384d..cb4ce61385 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:58c03e354b108033873e2a4c0b043ce15919c4d0630e6ca72ff70b89cbedb979 -size 44239 +oid sha256:5f844bf243df10178cdc8bd0d49fa8e7722476373c5b2cbc494bdc53eaa7a116 +size 44133 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png index a2bbce465e..7669d9686e 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f987f4d270568facefc11eee7f81dd156af56c26b69fe3a6d2d2e9818652befa -size 43116 +oid sha256:b80161aa7723ac8804a2679fbb1fc8327961166475e1a3567ee7bf1f61b43307 +size 41530 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png index 727a45d0b1..cc825e03f7 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ebdad83936e50bbb00fd74b7dd7d2f5a480bb7347aa3d151e7827107cd279bac -size 44441 +oid sha256:69e745d55bb37c75c5651713648fb9d2d761b8790b86b67e9a553a7ae6328f0a +size 43625 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png index 5f9b599b7d..9710298a3d 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccdf5937c30999e3b09071200de2e1db63b606ad9cbf6f7677a7499fb0b52963 -size 44252 +oid sha256:a2a534bc0862e0d7325e9d6bbdf1c73ddc356bd621dfdc64a9c0c04399a93e00 +size 43807 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png index b50fce4dc1..e6fc9aa0fe 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:baf70b732646d7c6cec60cfbe569ec673418dfb2dd0b5937bccfb91d9821d586 -size 45053 +oid sha256:4ba2d0740f6d614725125c393ed8cf19e0dc648a82b114de5b8531a97e828351 +size 43868 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png index dfdb4f642f..3251f0466d 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f6a1eae610ed730e4cec41693829929ba8db674886c2bd558f1b8893d2b76802 -size 51201 +oid sha256:a980061a57ac57351b4ccedb34f915319373759753cf2d28fb604a968b87fb2f +size 50640 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png index c37ea9dcaf..7bf58cd3ef 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba674e0236c2e146c64a7f3e224c702030769304cd0fd624d1989536da341659 -size 52814 +oid sha256:4b64630a74a435fde316a2d6be140ef54b04fecbf5fa76e31014d92c9cd925db +size 52298 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png index d1ccc680b6..c7e3a05892 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:316231c8d837f864cf62dcc79fdce698dc8c45c0327372de42c2b89eac1d9f81 -size 51851 +oid sha256:3535fa1a240cc7c11e9bb233333894f8782ec67ac36708c8ee3baf905c2d3f65 +size 51268 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png index 35ab5b75b8..687cd1dbca 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b58144146585f50960dfd6ac5dc3f52238160287ae5f9b18c6796962cc3d2fd2 -size 51550 +oid sha256:e2d47f277bc904ed8c3b3bbfe636b647884511de39661bfd34cdcb2abe9f6a13 +size 50818 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png index fde570043d..dd21dc76da 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6515be764d7026a87cfeea2d58344c404e4f15908139a25f413d51cc7cc61a0c -size 52216 +oid sha256:ed86ea3844a13de5247bcb409c70ca4a8051cb18b6a3c298a5665f4573f89490 +size 51756 diff --git a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png index 48e4261f1e..6ea363a346 100644 --- a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png +++ b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ef5a85b2adde25b5f343a18420fe787f5e159029a361a15ef2d6322eb7bb81fb -size 944597 +oid sha256:968a3cfdec62a89823e711f7ed15e3c456a8e44b8f9d46268dd312693e04be00 +size 1028911 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png index a7730d4e65..939897ba91 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f4d36c8f7e5d5c0d798af5fb6bfad28ed0d628b880bea81efe0d54ac1fde86b2 -size 265268 +oid sha256:62b08eae3bbcc99c2dace7156dae8e37786416e1e428455417b3efc7cdcbd56a +size 240453 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png index d993923d48..5afed57042 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f165908729d723818b6c5843bd75298d987448e2cd4278dfe3f388a62025add -size 238396 +oid sha256:f240153a429da26fbe2ffcbce71ceeae47225c261002c242c34b2747823d0f9a +size 231151 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png index 223d3bc012..0a026b2179 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:34eaa0696da00838e591b2c48e7797641521f7f3feb01abbd774591c4dd6f200 -size 265546 +oid sha256:7700134ca070ccef3f027b70534a811e4a388d05b421ca91d9176d84310ddfc0 +size 237380 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png index 367db5ea10..9771816664 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:531594a2e47710545d96d0fd9a8cc86983233420172e0ced28df050df1a5e039 -size 239844 +oid sha256:4e46eddb5225c37cfe20a4d94af0eabd1def78eb379a17d9cdae5fae0866d2bb +size 208360 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png index 922c2bf9b2..9771816664 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4f1462733e02d499b0d8c61ab835a27c7fee560fdc7fc521d20ec09bb4ccc80f -size 216030 +oid sha256:4e46eddb5225c37cfe20a4d94af0eabd1def78eb379a17d9cdae5fae0866d2bb +size 208360 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png index 29c93d14e2..cce6455851 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7e6d91a3ec4f974af675dc360fd5fd623ec8773cdbc88c0a3a6506880838718a -size 226727 +oid sha256:344efea18d09c8c9b23d7c06a8e865c271dc6acdc9330b589d9ebe15b48c285f +size 215670 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png index f8b5e61332..a5433fa6ea 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:620463c14de12abb4f2cab3ee6259ad8cbb24c688212729535f41ebf492a8836 -size 224490 +oid sha256:c32da9b861ac38306d1bfcae6384e4cdf449cfdb9de1fee3fdb6975e4096aea6 +size 212659 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png index dbfab2b508..a5433fa6ea 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c68eba122814b5470e5f2e03e34190ff79e84e4b431ad8227355ce7ffcd4a6a7 -size 220192 +oid sha256:c32da9b861ac38306d1bfcae6384e4cdf449cfdb9de1fee3fdb6975e4096aea6 +size 212659 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png index 86655af42b..284b8ad041 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6dbd3189b559941f91dd6e0aa15b34a3e5081477400678c2396c6a66d398876f -size 230883 +oid sha256:60fcd8cf74e595b9f5add7ef6924e4ed801f3835b7d2873bbc79e0b61b98bb0f +size 218566 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png index a9e5e18dfa..430f98d007 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:274c3e57f186c47bb070dfd2a79b8353032f9d91d03a3ab9ecb3aec13fdd9855 -size 273333 +oid sha256:3a650e180ee2f073f5d06ef343f5d14cde568777a21d8f419dae6c23f36bfb66 +size 255237 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png index d8a1178adc..f75e878311 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:df63a3d12e2998d5242b64169ac86e3df7ab4be585a80daddc3e3888dfcb7095 -size 262298 +oid sha256:934c4a8fd38d2d360dd1b69627043895975ee33ed63e2b1e514b8c6f8451c3f0 +size 253854 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png index 76946ee06f..558f8a545c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:457a0b4e27a09440ff4e13792b68fb5a9da82b7ce6129ea15a5ea8dcd99bd522 -size 274300 +oid sha256:38a6c8caeef772c51508954483810ecf4aa13168a8ec33af266cde028ee19f75 +size 249584 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png index b5cb6c0fa8..fb9b5513c5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fd007786164af8f410bd9738c0a072fc75d1f9b50145e5c191c9e3df345341a5 -size 318778 +oid sha256:649e8a71ba3328af6a48a0afe8747433bce459bed50ba5f4108343265f07cdf2 +size 314905 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png index 7e3080562c..77d1cc1153 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0203ecb9e4665e7c3992b7da4777c6d35b539790506fc9ca2acbcbc2bdb5db18 -size 303979 +oid sha256:d484a8d20c288de3f30b6c8ea2cecb6893d618d96e8a9079c0003ee49c798967 +size 303608 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png index 5626fa1b83..34ba72d102 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62cdce27fc46a38a16995df8ed1501f65091d69315288479b1d613b1d87c8239 -size 321123 +oid sha256:6b935deeff7a6f9be835f1975513b0063090d52e5d4178da1ce8575909729164 +size 320831 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png index 3ae9d369d6..c575778e08 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08ace2edc5089a7742c1c8005126dcce850b1adf9c017b12db6892f4daeef1bb -size 271721 +oid sha256:c14e3f64a9fa9487c4828bc931338525663177828d65f31928b1acf6f5c1d3a7 +size 269542 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png index 0205626738..c575778e08 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a2aae04edebcaca9b95f30963201794887fa0eac954b64c68bfe529b14fa9be -size 269397 +oid sha256:c14e3f64a9fa9487c4828bc931338525663177828d65f31928b1acf6f5c1d3a7 +size 269542 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png index 68d91fc437..02f91294f4 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f3e9a338a5ae37c88ce0c348e0b655429220da051db3352779c277bb2dcb441 -size 270622 +oid sha256:fc2c4df81110029eeaf07419c6a5a823faba757aacf776241ad3171370f70338 +size 271393 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png index 11939c16cd..c6f8957eec 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6ac7cdcc2fbee0572a369bed29c51e1c9056a4f09c4e0750ecb34d65daf403d4 -size 287741 +oid sha256:4812a323ca35208e55faf476d342202b320a302df9475f40f8d96161e09ae7ea +size 284361 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png index 324bd92539..c6f8957eec 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:752760327cc1416c171a920f1e0e95e34eae6d78bd0c7393a3be427bf3c8e55c -size 284481 +oid sha256:4812a323ca35208e55faf476d342202b320a302df9475f40f8d96161e09ae7ea +size 284361 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png index 52bf2a163f..13974a84c0 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:293459538454e07bc9ea1e9df1fa5b0eb986fde7de42f6c25b43e4c8859bd28a -size 285370 +oid sha256:5022fb7d43ec6885efcd6e7513ad92019f28febb91e7e2b61c421bf96cfbb76c +size 285270 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png index 9702a635d8..7d07b09e14 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:be7812accadc6347d6df43c308f7293596f92d0d90cf0b6a8e48fac1f4144fc0 -size 320157 +oid sha256:eb153e0e3c50cc038f8ab215646dd2a1739e748fa4a7a04ef34ea2f6d8e0c22a +size 318803 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png index d94d57759f..9342757f60 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff094e6bafe81e818bcbac69018dcfe29366389dfca0d63d8e05ef42896ffe1d -size 317309 +oid sha256:0e09d63aaf5365a1f4ac44beef9f203c4217a7e158703d44b2b1007c413b1f0c +size 318179 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png index e016e3de69..5a9662e032 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ee0778aac671365dd0afae06cdcf8f36243bd9815f684b975f83e297bb694e63 -size 323979 +oid sha256:563e9bf52b4ac7be22bc15e6aaf8b39e508eb7e31cb90986fe559ac88ba40829 +size 324538 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png index 4b1e9fed20..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f -size 13818 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png index cdf5f1a963..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9c6617ebf10f2fe1608fbc2a3c75f1a86ff4e3835b5d3fd7fcc2e5d0a4e5bbb1 -size 14380 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png index 2ad42755c6..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5bb52f047f410e2b0bdcd8d186043f0d3b03835f39007775608fb05365ac9a20 -size 14616 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png index 4b1e9fed20..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f -size 13818 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png index aabb936bd8..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:47e0924ddbf191dca8932eb46b9c533d0983b9fbce956026b392d5fe589fb90a -size 14630 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png index 0fe9cd8672..3abeb03160 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ede7ffc5d07a09c7c5706e8e2554897d29acaabf71701191b0f689f2c22ae71 -size 17826 +oid sha256:14dfcd85d0331448c1e3ff447e7e789ad4fc24618b6a9c5d05468bdd6a2f2209 +size 20804 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png index 1e8cd88ffe..3102144a14 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f91c7f1f687c73dd909b629e40f703740270042507c47aa3834ccd38bf289dc3 -size 19394 +oid sha256:8e7df6174aad752e0f3846eeef5efc4bfc70b80e3622a54eba59f6dcd4673d87 +size 21802 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png index a9f7d76f80..f5c07ac7a7 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b836ab4e0f1c95fe5d553bf5bca37eac402ba431268d25e4641e86c952f5fdd -size 19802 +oid sha256:95c739dd75b7be9dea10c12dd69ea60095ac617de491a2ba8063c86cd1bd9aa3 +size 22060 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png index 4b1e9fed20..dae4b4e140 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:033bb9e0ce89ffe4abda4d409af5741958d4035f9c9824c28d7598d72c4db96f -size 13818 +oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 +size 20936 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png index 958eee6ad7..e1bc766fbf 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00bcd2ac107f45cb31efee44de275dd597eae6d2d4fda71c397416ff5f2f0914 -size 20175 +oid sha256:f49ea178ca76bd1b2165b0b700a558433d27e22b07b3b35be3fdf3a1868d7ad6 +size 22371 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png index 881ee4e58a..dc3d45fa1d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b04b71b0a4718e5b3f91c33c23ef792fc81a67c9fef7b9e4d80bdb9dce3539dd -size 9107 +oid sha256:7bf316a54f0add7d92287fddc9cc3744d4be1a7ba7c6881d83d3f45356d2c53e +size 8627 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png index 6804454813..6f49f27154 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e0125454d2c3859d8457202856e21591ab96f61e2a29c3f017af29bf03961c48 -size 8883 +oid sha256:97c36988a937893cf106b7b7986fff32d0d90c882ed292010fc1172b1a149d22 +size 9388 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png index 52ba79e98b..3498290b81 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:213ebd9fc7a190ad7226b487387edb9452284193cee4c4720448d7e19ef38e76 -size 11149 +oid sha256:5e167ecea77962fa0b8376f1217cbba64c90c77e67213b229fba1c6122d2bc06 +size 11011 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png index fc26d1b766..0f00a00f84 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43b21e948795abb52ebbbf94e785542e55488cc7f17996e2b92404ca8ad1a7cb -size 7844 +oid sha256:b7fd78e11b8de40f646218597ec1ebccddbca7a6d901e5c87848ae1d9e0de361 +size 8390 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png index 6f67736dd6..93f1ca2343 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0bb8f730a43a8f58e4269905014461bab8dc8b47387ec86a84c1064b1cdabe14 -size 11813 +oid sha256:45f3bf5ae0e8061811eebd3328f1d8f7d54dc7b213f6324148c36292509a8ee5 +size 12761 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png index 22ce841b48..2b611ace6f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7500be583beb22759dec7e5bbb2a8d2230054366bfbd0e39bf10fdc8af63eb58 -size 8925 +oid sha256:36b1193c16c585918655bae2d98e4105b92cfab66ad903995f2af6b316e8b4a4 +size 9060 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png index 2457c12e91..44f7171246 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c48da7aad9c0aad576293d7085f9ddb2ea90a76d53bea54cbe0cb7aef71c7bb4 -size 9136 +oid sha256:71d5c7b4addc49a13e0adb60dc53b463845957ea5df490cd476f011b6770373e +size 9633 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png index 33ec41713e..67fcc5bf6c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:72e6c327e98d9929a4d850905b1471fcd1191088feb38b028e4240e9f93b4996 -size 9827 +oid sha256:8f0e458b747377aad809e48fdf6d7af69b1e523e1728d2367615bb7ce90c2680 +size 9733 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png index fc26d1b766..0d4f8c0f93 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:43b21e948795abb52ebbbf94e785542e55488cc7f17996e2b92404ca8ad1a7cb -size 7844 +oid sha256:08e2b6d31c842366175508fbe74c8ba546d0fa88f366ebb27279e38939b3bfa8 +size 8375 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png index ea35c328c4..7e124931c8 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70f8fc84d6e578822582ebee5888514dcd70c8d0da1a920f35e63a1617d1e92c -size 9841 +oid sha256:a7052b23b8d91947ba1f869f13ff99136096805e889558a741ce8e5eac3ece63 +size 9965 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png index e2b742ca45..a54b4088b6 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff4d6e3a7c8e69db0d5a88b7f1c91621692962bdbcedd6b8af1311506243bcde -size 11259 +oid sha256:5d5d5023535689657840dbf63d6343f4d1070cf5ec853586447eb8465da9640a +size 11444 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png index 61a28a9cfd..7b0ab347de 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:520910b75cae834b9844ce896ad9ab6d0b6c33c44c7bd822ce63752aaa2a8c5a -size 12122 +oid sha256:0f9ffc543dd312b3ca9d00f5444be214edfd78dbfb1a740556da3872b33623bf +size 12062 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png index bfaf9e30ab..1cf8978bcb 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e1fb4bb5d1591ac6bb8a4fb2504e2e836578c9c42d8286061cf4f57f0b7f97d -size 12876 +oid sha256:038d07eb02ed4fdfabfd97a4c7f4e1f1be25ae7ea874bac0ab192a18ea6be397 +size 12760 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png index 78576c467e..b5926ee62c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f5babf5f6ae746a9b9f131ecf990f037c8e8bdb257bdbb7f6127460c9b8f98d -size 10507 +oid sha256:cc402424e236ec35f0b510451533b1566dd9c4d4dea45af93aab8279f5f5abbe +size 10880 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png index 71d771fe36..3a24b61af1 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:56a9088fdca14b82fa3ac3ecfb67b6b8e97e8d69b89907c8408e17861e8609e0 -size 14195 +oid sha256:92c44ac71bf6822f12c8e90e1727da8db6e802c293f7945e5e6f6a9c311faccf +size 14115 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png index a68c99d4d9..476a346c68 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7d4ef129d8846e6802997c0ace90abdc7412d232e9a31fc53f25bb9f32de08f2 -size 12665 +oid sha256:fcc5ba9e73231485a4cfc3d38a6692762b079aa4057c7b32177c982a64b786f2 +size 12632 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png index 992ae04257..e00a684ee5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69b5771a313aa777341d1460db94a7b3cc74b69c44f6c9d1a1b5b3734936e795 -size 12791 +oid sha256:36f5aea2b06ca8d8f04beac2abd75a3620913e16f4ae55173b3b5cb371924d3f +size 13256 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png index 7865b70d7a..6d8df6c27a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a56f72c5a12e6d216a32404c996e72721b4cf350d82071a43ebe44190adef94a -size 12895 +oid sha256:d77d1c95fcc3dbe43c34bc94733eb6e8b3d007d023883f9bf18c9d9373444882 +size 13287 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png index 78576c467e..b5926ee62c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3f5babf5f6ae746a9b9f131ecf990f037c8e8bdb257bdbb7f6127460c9b8f98d -size 10507 +oid sha256:cc402424e236ec35f0b510451533b1566dd9c4d4dea45af93aab8279f5f5abbe +size 10880 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png index 140af0ed89..9ecfcb1fff 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:39f85cb564a257381656fd969acaeda04016e09380133f772eb029e332aeaa95 -size 13482 +oid sha256:30f8c8275afb6c61803facee006f3a181151e4d3d09a398eba60704a8e799df9 +size 13834 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png index 1a53f430c6..fbe6fedca5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915 -size 13818 +oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c +size 15368 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png index 90823958c7..566e1befe4 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e96967a2a6362f42026ab2e2cdd82437e573c16a52c5631f7495cb30615441d -size 13841 +oid sha256:20f45d86bdedce746fcd807d4abd6eda645c10064233d84ecf12613bcdcfc131 +size 15372 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png index f0270cd0ac..40ede8647c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d5f9e9e4f7f48681d5b240d6df6ae282c6b9e896eacc1ad73f2a097975fa8d29 -size 14060 +oid sha256:70638fa2140e8400683ef7b2914cf877cbfe81a44847035239165e81357d9f55 +size 15707 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png index 1a53f430c6..fbe6fedca5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915 -size 13818 +oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c +size 15368 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png index 636f8299aa..be922bfe5d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97d6923c3342d600a9a2ab3fa713136b2649b74364d6e90a905de607838e0cb7 -size 14319 +oid sha256:a33e1510a59a7abd38ba4e97d18428aa76bc6bdad9016f2d279b996a8f0ea0a3 +size 16040 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png index f287f604e0..2debe15ab4 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66399a4ba262bdacdc5966fa9fc6f8f6bfa3f8c70db889363e9bbd5778dc1ecf -size 16081 +oid sha256:9a209b60feda34e2078fe0609e8e32a67901d1ec0d99fe500e4d7968031f62df +size 17253 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png index f6a36e2035..447ffb0ee6 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5953a12a2fa67f9fe17485c62d156bb7f80a4bcf4124c123db4440c2559e0e69 -size 17002 +oid sha256:5383256fd20787dcce51bf8d13af94172ea47e2bda8ae1285768d422c3d08f61 +size 17531 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png index 03519e0322..b991ad6599 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:efc08c6969344de404692c2b367130e3f736442c0722067a9105f036a9e4511e -size 17616 +oid sha256:b754d74a036eff2a56ebea8fce81d952db54f05c6ec247cfe5bb76eacbf0c33f +size 17949 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png index 1a53f430c6..fbe6fedca5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9d528ea896a2e56e0b8967d5ce3486078cbd7bf29e5f0d43a58ef21100147915 -size 13818 +oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c +size 15368 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png index c4c8d7aac3..cd3527df31 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:455488369cd943f3c3a0b2c402dbb17d6fc9c384b5f26dbc049634ad4bdab73f -size 18259 +oid sha256:fdf77c8222a40afcfdda5edeb87b7921c71b1368ac7f91cc560e8d73676fdb33 +size 18115 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png index ce6858e2d8..4013073c10 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a65ffa4c6b8488f52892306052337e17a4e58d28fa43f18009e6d1f997962de -size 83060 +oid sha256:374a09cf2f904bc512bafb1d280f5de484bf101bb7d24d4dfef0f5fe22f2ed39 +size 82110 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png index 651ed382fe..f8c459512b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1f69909cdc4b65548834e30caf44a31b7e5d41be1db05cb43bd8277613f327ed -size 55263 +oid sha256:2a4564e26e53e6562ca4dfa44e671150903e022db4f6ec76038627bca130bbe9 +size 54177 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png index 501074f232..834c5ffe6b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ff7d35f1ce04d8f2b6cee41c951487bd24e18f923dc84c77a7944ec3aab61540 -size 80844 +oid sha256:00ede0da073e60deba1f0eb7cc5f3da0902b44dfcea71cbf33a56fc74955823b +size 79449 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png index 08ddd2deff..7ceb6114ad 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:48ac9eea396e010b1c110413a6861b1708f3928243271ea78f390e64dfe11737 -size 62249 +oid sha256:7ce4b978b800820275635ae8da59212661c74a1b6ba9050ebf052c87315aedef +size 62107 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png index da68bff3ce..570db6a3a9 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a4786eb2c04be00302996f3ad65987f54fe5d80ded438fdcccf7b9bfe9520dbb -size 33930 +oid sha256:602181e876201b10f75650eb07961fa499c05009067c7d298d4826e1503b93ca +size 33091 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png index 5f9b599b7d..9710298a3d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ccdf5937c30999e3b09071200de2e1db63b606ad9cbf6f7677a7499fb0b52963 -size 44252 +oid sha256:a2a534bc0862e0d7325e9d6bbdf1c73ddc356bd621dfdc64a9c0c04399a93e00 +size 43807 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png index 60e5f18dc0..062113ae68 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:898c8524d6fcad8498a22dd97956265302458d43f8d3f93846c2268d7b47fb73 -size 35351 +oid sha256:8906591aa17712c67939d40ada949e10c8de0cdaac5186a88db1199ac1819bd3 +size 33835 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png index cf7cba1811..8fd221575a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f37abc44b703b6feac3a2a950df7f40a8a67fe64fa25c19af59862e5272f0ff -size 34311 +oid sha256:545a01286eff5b5835e79b595fe482f2f5e571972dfdbff651eb5db2944d7889 +size 33045 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png index 8ddd2cf001..877ed87781 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1cb4518f6b9e1ed1409b0f4e87c17ae990cff2725c650d69941cc76ba90b2f7b -size 44672 +oid sha256:2f34ecadac596bccfb2fcc5cc7f070ea98917a30d036bee558775c01737c72d2 +size 43016 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png index e2fc05dd92..7869d6f134 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:16a592718ba5aa15f79ef4864cba75fae5a7cc5e13ca56eeab5fd13a0e5347de -size 102049 +oid sha256:d713b040dbe51d9034cd7c3b1055b64a21c9146e6417c7c35f1012f4093b872c +size 104792 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png index fb44b61f9e..d6f69a5bde 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:86ebb09209d4bfbe266c633df1c7062755cd413f47d0a96a05bcf003a02cb12b -size 84428 +oid sha256:0773406e402e8c30bb345de5e4e20f2546a3ad692b9ad0b29dfe3df8c659cf4b +size 83576 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png index b4ff7af8d8..c8d7908efe 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:779521e132b4ee6b3ac7a9186fca3250c6d2ace7e55f4f6c9601fe5393d9eb10 -size 99561 +oid sha256:6b75b9c856570b0b2bfd8826eb8771bf15b74f309ee70aae72a607e96040e254 +size 99413 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png index 8b5956b1ac..b56b714e88 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a6d0b12e19b980fd558a4920ec18620a9bdb00bd1379a20719ff0ee92c6887a1 -size 96007 +oid sha256:7a609150bfad93dc56bf9e1c3214ea3eabec48dd73939945840656de544bd423 +size 94976 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png index e1122365e9..bd2913174b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:82c34b115c081a1f3723540b9a273724353930c53006dd6daea576a227271e01 -size 78599 +oid sha256:b06aa4d0f3caca205cb5adcdcf26bf6ec6157febdd9266a3fcda9179deaf0840 +size 77036 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png index 30cfcf2dea..ab2a2e3f6b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6fbe71277a196e5c57fba7caba5c0a1b2bff2da9eadbd7bab1ae1853fab2dd93 -size 92581 +oid sha256:66c47408a07b7e32d7cabc64289aa8f16b0c96e5ca4c478ebae48729ff55b229 +size 91645 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png index d79f324a77..0364487787 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b1061a363744661febdd051ef2f6839bfe288eb83f7ebf281fb06717fbe6703a -size 60739 +oid sha256:ded9cb4986e620f5fc11486ccdf81934dff7b3cea7db7e292929d339ecc21714 +size 60116 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png index 03baa702a7..a798459cb8 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cacd80b681c086310d3be7d90575da357e6ab0a62e24227a1e7e3ae4cab1de2d -size 46905 +oid sha256:5da4f2f3024fe3c8ae7f0ce6113f78c74d699eb4efe41f1d9df875af05d09547 +size 46806 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png index 35ab5b75b8..687cd1dbca 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b58144146585f50960dfd6ac5dc3f52238160287ae5f9b18c6796962cc3d2fd2 -size 51550 +oid sha256:e2d47f277bc904ed8c3b3bbfe636b647884511de39661bfd34cdcb2abe9f6a13 +size 50818 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png index dfcc0603dc..8e0f6002c6 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d54a2b762a16c76ad52919708d0126ae63958e9d900e3870cced695540e16192 -size 68366 +oid sha256:4324dc77448aeb0ee4ebe39c449ddedff81bf6f0243e0c4713ae89a18b13f0b8 +size 67273 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png index c1c66f8409..33c9d43247 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:87450152fdccfaebb55e22040206cb246bc59b61461fd8b6ca6e099256fa0f1d -size 63839 +oid sha256:eb0a2e6d50625ae9a67f9d36d3296f65e41bb6d5a7d3e8163dba89333e3ac6a3 +size 63442 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png index f79a145a6e..f3900e5f6c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7136f92f3fd1927e98204b1140ca36a901dcd9b67c17f7080413588c2e2dcc28 -size 69579 +oid sha256:6551261b6b8c4cf4f69ba2860e163fe10fc9f2660cbb43c1423a9b5dd9456040 +size 68497 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png index 79cec59e5f..6203feb92d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ab5972eaa6b008b9768f3af4c61957db3d6da41cdf52696c05ecd3f2efaf3d5f -size 113964 +oid sha256:5f5cf2a5917f8edf77cfc78b8d923bda672435da095876390bd14212bfd87d75 +size 112571 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png index 159e284c59..1625e16862 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:46c6b9eb83c6d4ffafc2163b0e0ccd5aa24ac56bb65e8cf5f02b80319cf29e4b -size 108931 +oid sha256:abd3ad65543bf9bdfb9924652cc107b23c80db3e210d2b994fd575ea73475aa7 +size 108014 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png index c11f7ac792..19a672d804 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f54b00e54e8786c9c9ff8e8cf7e42111e06e5dc5d2e69ee2c8c8be2353030e43 -size 114680 +oid sha256:a27a605acbd026ba475fae9110c69c6002a399ef3747ce7ca5c060a6df5a078b +size 114379 From 4f8ea7f677d2b857aedd87b0644c93dfe8e3592b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 24 Nov 2023 23:11:40 +1000 Subject: [PATCH 050/219] Tweak bounds clamping --- src/ImageSharp/Formats/AnimationUtilities.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index b66efd7f56..a3a5292a28 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -148,11 +148,12 @@ internal static class AnimationUtilities PixelOperations.Instance.FromVector4Destructive(configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span, PixelConversionModifiers.Scale); } - Rectangle bounds = Rectangle.FromLTRB( - left = Numerics.Clamp(left, 0, resultFrame.Width - 1), - top = Numerics.Clamp(top, 0, resultFrame.Height - 1), - Numerics.Clamp(right, left + 1, resultFrame.Width), - Numerics.Clamp(bottom, top + 1, resultFrame.Height)); + left = Math.Max(0, Math.Min(left, resultFrame.Width - 1)); + top = Math.Max(0, Math.Min(top, resultFrame.Height - 1)); + right = Math.Max(left + 1, Math.Min(right, resultFrame.Width)); + bottom = Math.Max(top + 1, Math.Min(bottom, resultFrame.Height)); + + Rectangle bounds = Rectangle.FromLTRB(left, top, right, bottom); // Webp requires even bounds if (clampingMode == ClampingMode.Even) From fabfd5bde1e1f15b75321027f5c9fd6835e5d8d1 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Fri, 24 Nov 2023 17:53:40 +0100 Subject: [PATCH 051/219] Added a couple of tests for CicpProfile --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 ++ .../Profiles/CICP/CicpProfileTests.cs | 72 +++++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/adamheadsHLG.png | 3 + 4 files changed, 82 insertions(+) create mode 100644 tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs create mode 100644 tests/Images/Input/Png/adamheadsHLG.png diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index a86fd17cca..4e8792c0ef 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -786,6 +786,12 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable return; } + // by spec, the matrix coefficients must be set to Identity + if (metaData.CicpProfile.MatrixCoefficients != Metadata.Profiles.CICP.CicpMatrixCoefficients.Identity) + { + throw new NotSupportedException("CICP matrix coefficients other than Identity are not supported in PNG"); + } + Span outputBytes = this.chunkDataBuffer.Span[..4]; outputBytes[0] = (byte)metaData.CicpProfile.ColorPrimaries; outputBytes[1] = (byte)metaData.CicpProfile.TransferCharacteristics; diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs new file mode 100644 index 0000000000..be215a0881 --- /dev/null +++ b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs @@ -0,0 +1,72 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using SixLabors.ImageSharp.Formats; +using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Metadata.Profiles.CICP; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Cicp; + +public class CicpProfileTests +{ + [Theory] + [WithFile(TestImages.Png.AdamHeadsHlg, PixelTypes.Rgba64)] + public async Task ReadCicpMetadata_FromPng_Works(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = await provider.GetImageAsync(PngDecoder.Instance)) + { + CicpProfile actual = image.Metadata.CicpProfile ?? image.Frames.RootFrame.Metadata.CicpProfile; + CicpProfileContainsExpectedValues(actual); + } + } + + [Fact] + public void WritingPng_PreservesCicpProfile() + { + // arrange + using var image = new Image(1, 1); + var original = new CicpProfile() + { + ColorPrimaries = CicpColorPrimaries.ItuRBt2020_2, + TransferCharacteristics = CicpTransferCharacteristics.SmpteSt2084, + MatrixCoefficients = CicpMatrixCoefficients.Identity, + FullRange = true, + }; + image.Metadata.CicpProfile = original; + var encoder = new PngEncoder(); + + // act + using Image reloadedImage = WriteAndRead(image, encoder); + + // assert + CicpProfile actual = reloadedImage.Metadata.CicpProfile ?? reloadedImage.Frames.RootFrame.Metadata.CicpProfile; + Assert.NotNull(actual); + Assert.Equal(actual.ColorPrimaries, original.ColorPrimaries); + Assert.Equal(actual.TransferCharacteristics, original.TransferCharacteristics); + Assert.Equal(actual.MatrixCoefficients, original.MatrixCoefficients); + Assert.Equal(actual.FullRange, original.FullRange); + } + + private static void CicpProfileContainsExpectedValues(CicpProfile cicp) + { + Assert.NotNull(cicp); + Assert.Equal(CicpColorPrimaries.ItuRBt2020_2, cicp.ColorPrimaries); + Assert.Equal(CicpTransferCharacteristics.AribStdB67, cicp.TransferCharacteristics); + Assert.Equal(CicpMatrixCoefficients.Identity, cicp.MatrixCoefficients); + Assert.True(cicp.FullRange); + } + + private static Image WriteAndRead(Image image, IImageEncoder encoder) + { + using (var memStream = new MemoryStream()) + { + image.Save(memStream, encoder); + image.Dispose(); + + memStream.Position = 0; + return Image.Load(memStream); + } + } +} diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6ad93adfbd..4c4882a951 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -61,6 +61,7 @@ public static class TestImages public const string TestPattern31x31 = "Png/testpattern31x31.png"; public const string TestPattern31x31HalfTransparent = "Png/testpattern31x31-halftransparent.png"; public const string XmpColorPalette = "Png/xmp-colorpalette.png"; + public const string AdamHeadsHlg = "Png/adamHeadsHLG.png"; // Animated // https://philip.html5.org/tests/apng/tests.html diff --git a/tests/Images/Input/Png/adamheadsHLG.png b/tests/Images/Input/Png/adamheadsHLG.png new file mode 100644 index 0000000000..f5d26ac50c --- /dev/null +++ b/tests/Images/Input/Png/adamheadsHLG.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8c50691da3b3af21ff4f8fc30f1313bc412b84fb0a07a5bf3b8b14eae7581ade +size 201440 From b30698c53c8f736d5602becf71197f8daaa04f33 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Fri, 24 Nov 2023 18:09:58 +0100 Subject: [PATCH 052/219] Cleanups (capitalization, tests) --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- src/ImageSharp/Metadata/ImageFrameMetadata.cs | 2 +- src/ImageSharp/Metadata/ImageMetadata.cs | 2 +- .../Metadata/Profiles/CICP/CicpProfile.cs | 4 +- .../Profiles/CICP/Enums/CicpColorPrimaries.cs | 2 +- .../CICP/Enums/CicpMatrixCoefficients.cs | 2 +- .../CICP/Enums/CicpTransferCharacteristics.cs | 4 +- .../Profiles/CICP/CicpProfileTests.cs | 46 +++++++++++-------- 9 files changed, 38 insertions(+), 28 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index acb97ed893..26bcaed27c 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -16,7 +16,7 @@ using SixLabors.ImageSharp.Formats.Png.Filters; using SixLabors.ImageSharp.IO; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; -using SixLabors.ImageSharp.Metadata.Profiles.CICP; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 4e8792c0ef..3ce6170b52 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -787,7 +787,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable } // by spec, the matrix coefficients must be set to Identity - if (metaData.CicpProfile.MatrixCoefficients != Metadata.Profiles.CICP.CicpMatrixCoefficients.Identity) + if (metaData.CicpProfile.MatrixCoefficients != Metadata.Profiles.Cicp.CicpMatrixCoefficients.Identity) { throw new NotSupportedException("CICP matrix coefficients other than Identity are not supported in PNG"); } diff --git a/src/ImageSharp/Metadata/ImageFrameMetadata.cs b/src/ImageSharp/Metadata/ImageFrameMetadata.cs index f02ef39c48..1c0330d5d0 100644 --- a/src/ImageSharp/Metadata/ImageFrameMetadata.cs +++ b/src/ImageSharp/Metadata/ImageFrameMetadata.cs @@ -2,7 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Metadata.Profiles.CICP; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; diff --git a/src/ImageSharp/Metadata/ImageMetadata.cs b/src/ImageSharp/Metadata/ImageMetadata.cs index c6ff6fe73e..db6e6094e0 100644 --- a/src/ImageSharp/Metadata/ImageMetadata.cs +++ b/src/ImageSharp/Metadata/ImageMetadata.cs @@ -2,7 +2,7 @@ // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.Formats; -using SixLabors.ImageSharp.Metadata.Profiles.CICP; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Iptc; diff --git a/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs index 5d6e357c47..2657903dfa 100644 --- a/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs +++ b/src/ImageSharp/Metadata/Profiles/CICP/CicpProfile.cs @@ -1,10 +1,10 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; +namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp; /// -/// Represents a CICP profile as per ITU-T H.273 / ISO/IEC 23091-2_2019 providing access to color space information +/// Represents a Cicp profile as per ITU-T H.273 / ISO/IEC 23091-2_2019 providing access to color space information /// public sealed class CicpProfile : IDeepCloneable { diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs index 390c6a263e..bab888dd71 100644 --- a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpColorPrimaries.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; +namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp; #pragma warning disable CA1707 // Underscores in enum members diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs index 6b421ab9b1..931beac846 100644 --- a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpMatrixCoefficients.cs @@ -1,7 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; +namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp; #pragma warning disable CA1707 // Underscores in enum members diff --git a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs index f9bc8d90e5..86eea0b70d 100644 --- a/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs +++ b/src/ImageSharp/Metadata/Profiles/CICP/Enums/CicpTransferCharacteristics.cs @@ -1,9 +1,9 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -namespace SixLabors.ImageSharp.Metadata.Profiles.CICP; +namespace SixLabors.ImageSharp.Metadata.Profiles.Cicp; -#pragma warning disable CA1707 // Underscores in enum members +#pragma warning disable CA1707 // Underscores in enum values /// /// Transfer characteristics according to ITU-T H.273 / ISO/IEC 23091-2_2019 subclause 8.2 diff --git a/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs index be215a0881..76e2d35c45 100644 --- a/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs +++ b/tests/ImageSharp.Tests/Metadata/Profiles/CICP/CicpProfileTests.cs @@ -3,7 +3,7 @@ using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Png; -using SixLabors.ImageSharp.Metadata.Profiles.CICP; +using SixLabors.ImageSharp.Metadata.Profiles.Cicp; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.Metadata.Profiles.Cicp; @@ -15,11 +15,10 @@ public class CicpProfileTests public async Task ReadCicpMetadata_FromPng_Works(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using (Image image = await provider.GetImageAsync(PngDecoder.Instance)) - { - CicpProfile actual = image.Metadata.CicpProfile ?? image.Frames.RootFrame.Metadata.CicpProfile; - CicpProfileContainsExpectedValues(actual); - } + using Image image = await provider.GetImageAsync(PngDecoder.Instance); + + CicpProfile actual = image.Metadata.CicpProfile ?? image.Frames.RootFrame.Metadata.CicpProfile; + CicpProfileContainsExpectedValues(actual); } [Fact] @@ -27,13 +26,7 @@ public class CicpProfileTests { // arrange using var image = new Image(1, 1); - var original = new CicpProfile() - { - ColorPrimaries = CicpColorPrimaries.ItuRBt2020_2, - TransferCharacteristics = CicpTransferCharacteristics.SmpteSt2084, - MatrixCoefficients = CicpMatrixCoefficients.Identity, - FullRange = true, - }; + var original = CreateCicpProfile(); image.Metadata.CicpProfile = original; var encoder = new PngEncoder(); @@ -42,11 +35,7 @@ public class CicpProfileTests // assert CicpProfile actual = reloadedImage.Metadata.CicpProfile ?? reloadedImage.Frames.RootFrame.Metadata.CicpProfile; - Assert.NotNull(actual); - Assert.Equal(actual.ColorPrimaries, original.ColorPrimaries); - Assert.Equal(actual.TransferCharacteristics, original.TransferCharacteristics); - Assert.Equal(actual.MatrixCoefficients, original.MatrixCoefficients); - Assert.Equal(actual.FullRange, original.FullRange); + CicpProfileIsValidAndEqual(actual, original); } private static void CicpProfileContainsExpectedValues(CicpProfile cicp) @@ -58,6 +47,27 @@ public class CicpProfileTests Assert.True(cicp.FullRange); } + private static CicpProfile CreateCicpProfile() + { + var profile = new CicpProfile() + { + ColorPrimaries = CicpColorPrimaries.ItuRBt2020_2, + TransferCharacteristics = CicpTransferCharacteristics.SmpteSt2084, + MatrixCoefficients = CicpMatrixCoefficients.Identity, + FullRange = true, + }; + return profile; + } + + private static void CicpProfileIsValidAndEqual(CicpProfile actual, CicpProfile original) + { + Assert.NotNull(actual); + Assert.Equal(actual.ColorPrimaries, original.ColorPrimaries); + Assert.Equal(actual.TransferCharacteristics, original.TransferCharacteristics); + Assert.Equal(actual.MatrixCoefficients, original.MatrixCoefficients); + Assert.Equal(actual.FullRange, original.FullRange); + } + private static Image WriteAndRead(Image image, IImageEncoder encoder) { using (var memStream = new MemoryStream()) From b46ab5af846cf189fca84464a47f0b6c9c617224 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Fri, 24 Nov 2023 19:16:21 +0100 Subject: [PATCH 053/219] Explicitly set BitsPerPixel and BitsPerSample to 1 for bicolor compressed images, fixes #2587 --- .../Formats/Tiff/TiffDecoderOptionsParser.cs | 28 +++++++++++++++++-- .../Formats/Tiff/TiffDecoderTests.cs | 6 ++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Tiff/Issues/Issue2587.tiff | 3 ++ 4 files changed, 36 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tiff/Issues/Issue2587.tiff diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs index 26905965ee..5a5c2b3e51 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderOptionsParser.cs @@ -139,8 +139,8 @@ internal static class TiffDecoderOptionsParser options.OldJpegCompressionStartOfImageMarker = jpegInterchangeFormatValue.Value; } - options.ParseColorType(exifProfile); options.ParseCompression(frameMetadata.Compression, exifProfile); + options.ParseColorType(exifProfile); bool isTiled = VerifyRequiredFieldsArePresent(exifProfile, frameMetadata, options.PlanarConfiguration); @@ -194,7 +194,9 @@ internal static class TiffDecoderOptionsParser } } - if (frameMetadata.BitsPerPixel == null) + // For BiColor compressed images, the BitsPerPixel value will be set explicitly to 1, so we don't throw in those cases. + // See: https://github.com/SixLabors/ImageSharp/issues/2587 + if (frameMetadata.BitsPerPixel == null && !IsBiColorCompression(frameMetadata.Compression)) { TiffThrowHelper.ThrowNotSupported("The TIFF BitsPerSample entry is missing which is required to decode the image!"); } @@ -570,6 +572,11 @@ internal static class TiffDecoderOptionsParser options.FaxCompressionOptions = FaxCompressionOptions.None; } + // Some encoders do not set the BitsPerSample correctly, so we set those values here to the required values: + // https://github.com/SixLabors/ImageSharp/issues/2587 + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } @@ -585,12 +592,18 @@ internal static class TiffDecoderOptionsParser options.FaxCompressionOptions = FaxCompressionOptions.None; } + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } case TiffCompression.Ccitt1D: { options.CompressionType = TiffDecoderCompressionType.HuffmanRle; + options.BitsPerSample = new TiffBitsPerSample(1, 0, 0); + options.BitsPerPixel = 1; + break; } @@ -645,4 +658,15 @@ internal static class TiffDecoderOptionsParser } } } + + private static bool IsBiColorCompression(TiffCompression? compression) + { + if (compression is TiffCompression.Ccitt1D or TiffCompression.CcittGroup3Fax or + TiffCompression.CcittGroup4Fax) + { + return true; + } + + return false; + } } diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs index decc0069a5..ab49805a35 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffDecoderTests.cs @@ -665,6 +665,12 @@ public class TiffDecoderTests : TiffDecoderBaseTester public void TiffDecoder_CanDecode_TiledWithNonEqualWidthAndHeight(TestImageProvider provider) where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + // https://github.com/SixLabors/ImageSharp/issues/2587 + [Theory] + [WithFile(Issues2587, PixelTypes.Rgba32)] + public void TiffDecoder_CanDecode_BiColorWithMissingBitsPerSample(TestImageProvider provider) + where TPixel : unmanaged, IPixel => TestTiffDecoder(provider); + [Theory] [WithFile(JpegCompressedGray0000539558, PixelTypes.Rgba32)] public void TiffDecoder_ThrowsException_WithCircular_IFD_Offsets(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6ad93adfbd..1675580c02 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -992,6 +992,7 @@ public static class TestImages public const string Issues2149 = "Tiff/Issues/Group4CompressionWithStrips.tiff"; public const string Issues2255 = "Tiff/Issues/Issue2255.png"; public const string Issues2435 = "Tiff/Issues/Issue2435.tiff"; + public const string Issues2587 = "Tiff/Issues/Issue2587.tiff"; public const string JpegCompressedGray0000539558 = "Tiff/Issues/JpegCompressedGray-0000539558.tiff"; public const string Tiled0000023664 = "Tiff/Issues/tiled-0000023664.tiff"; diff --git a/tests/Images/Input/Tiff/Issues/Issue2587.tiff b/tests/Images/Input/Tiff/Issues/Issue2587.tiff new file mode 100644 index 0000000000..55368e1d3a --- /dev/null +++ b/tests/Images/Input/Tiff/Issues/Issue2587.tiff @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5a245e4313bcf942d9a8ab7108946ddcadcf45d898b8a8986fc42a6e8c64dc2 +size 87746 From c306c56ce5616fc4ed12d469bc0f29bfb7a0b15e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 25 Nov 2023 16:50:32 +1000 Subject: [PATCH 054/219] Use correct buffer dimensions --- src/ImageSharp/Formats/AnimationUtilities.cs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index a3a5292a28..82003d4b64 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -148,12 +148,11 @@ internal static class AnimationUtilities PixelOperations.Instance.FromVector4Destructive(configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span, PixelConversionModifiers.Scale); } - left = Math.Max(0, Math.Min(left, resultFrame.Width - 1)); - top = Math.Max(0, Math.Min(top, resultFrame.Height - 1)); - right = Math.Max(left + 1, Math.Min(right, resultFrame.Width)); - bottom = Math.Max(top + 1, Math.Min(bottom, resultFrame.Height)); - - Rectangle bounds = Rectangle.FromLTRB(left, top, right, bottom); + Rectangle bounds = Rectangle.FromLTRB( + left = Numerics.Clamp(left, 0, resultFrame.Width - 1), + top = Numerics.Clamp(top, 0, resultFrame.Height - 1), + Numerics.Clamp(right, left + 1, resultFrame.Width), + Numerics.Clamp(bottom, top + 1, resultFrame.Height)); // Webp requires even bounds if (clampingMode == ClampingMode.Even) @@ -172,7 +171,7 @@ internal static class AnimationUtilities { Buffer2DRegion sourceBuffer = source.PixelBuffer.GetRegion(bounds); Buffer2DRegion destBuffer = destination.PixelBuffer.GetRegion(bounds); - for (int y = 0; y < destination.Height; y++) + for (int y = 0; y < destBuffer.Height; y++) { Span sourceRow = sourceBuffer.DangerousGetRowSpan(y); Span destRow = destBuffer.DangerousGetRowSpan(y); From 6cda7b03c66b8146c1fd7d73e32c578cc1247b3c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 26 Nov 2023 22:13:40 +1000 Subject: [PATCH 055/219] Fix scanline lengths --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 18 ++++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 24bb3c00e1..37e31f32d7 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -176,7 +176,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { if (image.Metadata.TryGetGifMetadata(out GifMetadata? gif)) { - return gif; + return (GifMetadata)gif.DeepClone(); } if (image.Metadata.TryGetPngMetadata(out PngMetadata? png)) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index cb4f599eb8..a1be79759b 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -764,10 +764,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { cancellationToken.ThrowIfCancellationRequested(); int bytesPerFrameScanline = this.CalculateScanlineLength((int)frameControl.Width) + 1; - Span scanlineSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; + Span scanSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; + Span prevSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; + while (currentRowBytesRead < bytesPerFrameScanline) { - int bytesRead = compressedStream.Read(scanlineSpan, currentRowBytesRead, bytesPerFrameScanline - currentRowBytesRead); + int bytesRead = compressedStream.Read(scanSpan, currentRowBytesRead, bytesPerFrameScanline - currentRowBytesRead); if (bytesRead <= 0) { return; @@ -778,25 +780,25 @@ internal sealed class PngDecoderCore : IImageDecoderInternals currentRowBytesRead = 0; - switch ((FilterType)scanlineSpan[0]) + switch ((FilterType)scanSpan[0]) { case FilterType.None: break; case FilterType.Sub: - SubFilter.Decode(scanlineSpan, this.bytesPerPixel); + SubFilter.Decode(scanSpan, this.bytesPerPixel); break; case FilterType.Up: - UpFilter.Decode(scanlineSpan, this.previousScanline.GetSpan()); + UpFilter.Decode(scanSpan, prevSpan); break; case FilterType.Average: - AverageFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel); + AverageFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; case FilterType.Paeth: - PaethFilter.Decode(scanlineSpan, this.previousScanline.GetSpan(), this.bytesPerPixel); + PaethFilter.Decode(scanSpan, prevSpan, this.bytesPerPixel); break; default: @@ -804,7 +806,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; } - this.ProcessDefilteredScanline(frameControl, currentRow, scanlineSpan, imageFrame, pngMetadata, blendRowBuffer); + this.ProcessDefilteredScanline(frameControl, currentRow, scanSpan, imageFrame, pngMetadata, blendRowBuffer); this.SwapScanlineBuffers(); currentRow++; } From 90fa817135295b1c2a89a98f8ebbb0f63108285e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 26 Nov 2023 22:40:10 +1000 Subject: [PATCH 056/219] Update PngDecoderCore.cs --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a1be79759b..5bbfc39e37 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -765,7 +765,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals cancellationToken.ThrowIfCancellationRequested(); int bytesPerFrameScanline = this.CalculateScanlineLength((int)frameControl.Width) + 1; Span scanSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; - Span prevSpan = this.scanline.GetSpan()[..bytesPerFrameScanline]; + Span prevSpan = this.previousScanline.GetSpan()[..bytesPerFrameScanline]; while (currentRowBytesRead < bytesPerFrameScanline) { From 4029b15bd670f220e32167d50bc53c0c10e7bf31 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 26 Nov 2023 22:41:20 +1000 Subject: [PATCH 057/219] Remove duplicate condition check --- src/ImageSharp/Formats/AnimationUtilities.cs | 60 ++++++++++---------- 1 file changed, 29 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 82003d4b64..486b4027a7 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -74,40 +74,38 @@ internal static class AnimationUtilities uint x = 0; int length = current.Length; int remaining = current.Length; - if (Avx2.IsSupported && remaining >= 2) + + while (Avx2.IsSupported && remaining >= 2) { - while (remaining >= 2) + Vector256 p = Unsafe.Add(ref previousBase, x); + Vector256 c = Unsafe.Add(ref currentBase, x); + + // Compare the previous and current pixels + Vector256 mask = Avx2.CompareEqual(p.AsInt32(), c.AsInt32()); + mask = Avx2.CompareEqual(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); + mask = Avx2.And(mask, Avx2.Shuffle(mask, 0b_01_00_11_10)).AsInt32(); + + Vector256 neq = Avx2.Xor(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); + int m = Avx2.MoveMask(neq.AsByte()); + if (m != 0) { - Vector256 p = Unsafe.Add(ref previousBase, x); - Vector256 c = Unsafe.Add(ref currentBase, x); - - // Compare the previous and current pixels - Vector256 mask = Avx2.CompareEqual(p.AsInt32(), c.AsInt32()); - mask = Avx2.CompareEqual(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); - mask = Avx2.And(mask, Avx2.Shuffle(mask, 0b_01_00_11_10)).AsInt32(); - - Vector256 neq = Avx2.Xor(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); - int m = Avx2.MoveMask(neq.AsByte()); - if (m != 0) - { - // If is diff is found, the left side is marked by the min of previously found left side and the start position. - // The right is the max of the previously found right side and the end position. - int start = i + (BitOperations.TrailingZeroCount(m) / size); - int end = i + (2 - (BitOperations.LeadingZeroCount((uint)m) / size)); - left = Math.Min(left, start); - right = Math.Max(right, end); - hasRowDiff = true; - hasDiff = true; - } - - // Replace the pixel value with the replacement if the full pixel is matched. - Vector256 r = Avx.BlendVariable(c, replacement256, mask.AsSingle()); - Unsafe.Add(ref resultBase, x) = r; - - x++; - i += 2; - remaining -= 2; + // If is diff is found, the left side is marked by the min of previously found left side and the start position. + // The right is the max of the previously found right side and the end position. + int start = i + (BitOperations.TrailingZeroCount(m) / size); + int end = i + (2 - (BitOperations.LeadingZeroCount((uint)m) / size)); + left = Math.Min(left, start); + right = Math.Max(right, end); + hasRowDiff = true; + hasDiff = true; } + + // Replace the pixel value with the replacement if the full pixel is matched. + Vector256 r = Avx.BlendVariable(c, replacement256, mask.AsSingle()); + Unsafe.Add(ref resultBase, x) = r; + + x++; + i += 2; + remaining -= 2; } for (i = remaining; i > 0; i--) From 44b031132e69a60f317b0361c43d1998420d83ef Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 26 Nov 2023 22:43:25 +1000 Subject: [PATCH 058/219] Remove "new" --- src/ImageSharp/Formats/AnimationUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 486b4027a7..4e322d2a25 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -161,7 +161,7 @@ internal static class AnimationUtilities bounds.Y = Math.Max(0, bounds.Y - (bounds.Y & 1)); } - return new(hasDiff, bounds); + return (hasDiff, bounds); } public static void CopySource(ImageFrame source, ImageFrame destination, Rectangle bounds) From 55e69c7bd24c10b48c744ffcda6db8c164bd483d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 26 Nov 2023 23:00:38 +1000 Subject: [PATCH 059/219] Try disabling new high memory tests on failing platforms. --- tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs | 10 ++++++++++ tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 10 ++++++++++ .../ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs | 10 ++++++++++ 3 files changed, 30 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs index d6d63baabf..a7e16f7737 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifEncoderTests.cs @@ -275,6 +275,11 @@ public class GifEncoderTests public void Encode_AnimatedFormatTransform_FromPng(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(PngDecoder.Instance); using MemoryStream memStream = new(); @@ -318,6 +323,11 @@ public class GifEncoderTests public void Encode_AnimatedFormatTransform_FromWebp(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(WebpDecoder.Instance); using MemoryStream memStream = new(); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index f8fc774b78..6679a765f5 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -483,6 +483,11 @@ public partial class PngEncoderTests public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(GifDecoder.Instance); using MemoryStream memStream = new(); @@ -530,6 +535,11 @@ public partial class PngEncoderTests public void Encode_AnimatedFormatTransform_FromWebp(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(WebpDecoder.Instance); using MemoryStream memStream = new(); diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs index 6baacb38ce..acca49dcf4 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpEncoderTests.cs @@ -67,6 +67,11 @@ public class WebpEncoderTests public void Encode_AnimatedFormatTransform_FromGif(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(GifDecoder.Instance); using MemoryStream memStream = new(); @@ -109,6 +114,11 @@ public class WebpEncoderTests public void Encode_AnimatedFormatTransform_FromPng(TestImageProvider provider) where TPixel : unmanaged, IPixel { + if (TestEnvironment.RunsOnCI && !TestEnvironment.IsWindows) + { + return; + } + using Image image = provider.GetImage(PngDecoder.Instance); using MemoryStream memStream = new(); From a6f96f775e5724ea1fa99cddb2db7b3f5da7aee7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 28 Nov 2023 22:39:09 +1000 Subject: [PATCH 060/219] Optimize and fix deduper --- src/ImageSharp/Formats/AnimationUtilities.cs | 142 +++++++++--------- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 14 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 28 ++-- .../Formats/Webp/WebpEncoderCore.cs | 58 +++---- tests/ImageSharp.Tests/TestImages.cs | 2 + tests/Images/Input/Gif/m4nb.gif | 3 + 6 files changed, 137 insertions(+), 110 deletions(-) create mode 100644 tests/Images/Input/Gif/m4nb.gif diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 4e322d2a25..23fc40cdfe 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -25,26 +25,31 @@ internal static class AnimationUtilities /// The configuration. /// The previous frame if present. /// The current frame. + /// The next frame if present. /// The resultant output. /// The value to use when replacing duplicate pixels. + /// Whether the resultant frame represents an animation blend. /// The clamping bound to apply when calculating difference bounds. /// The representing the operation result. public static (bool Difference, Rectangle Bounds) DeDuplicatePixels( Configuration configuration, ImageFrame? previousFrame, ImageFrame currentFrame, + ImageFrame? nextFrame, ImageFrame resultFrame, - Vector4 replacement, + Color replacement, + bool blend, ClampingMode clampingMode = ClampingMode.None) where TPixel : unmanaged, IPixel { - // TODO: This would be faster (but more complicated to find diff bounds) if we operated on Rgba32. - // If someone wants to do that, they have my unlimited thanks. MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 3, AllocationOptions.Clean); - Span previous = buffers.GetSpan()[..currentFrame.Width]; - Span current = buffers.GetSpan().Slice(currentFrame.Width, currentFrame.Width); - Span result = buffers.GetSpan()[(currentFrame.Width * 2)..]; + IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 4, AllocationOptions.Clean); + Span previous = buffers.GetSpan()[..currentFrame.Width]; + Span current = buffers.GetSpan().Slice(currentFrame.Width, currentFrame.Width); + Span next = buffers.GetSpan().Slice(currentFrame.Width * 2, currentFrame.Width); + Span result = buffers.GetSpan()[(currentFrame.Width * 3)..]; + + Rgba32 bg = replacement; int top = int.MinValue; int bottom = int.MaxValue; @@ -56,70 +61,90 @@ internal static class AnimationUtilities { if (previousFrame != null) { - PixelOperations.Instance.ToVector4(configuration, previousFrame.DangerousGetPixelRowMemory(y).Span, previous, PixelConversionModifiers.Scale); + PixelOperations.Instance.ToRgba32(configuration, previousFrame.DangerousGetPixelRowMemory(y).Span, previous); } - PixelOperations.Instance.ToVector4(configuration, currentFrame.DangerousGetPixelRowMemory(y).Span, current, PixelConversionModifiers.Scale); - - ref Vector256 previousBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(previous)); - ref Vector256 currentBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(current)); - ref Vector256 resultBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); + PixelOperations.Instance.ToRgba32(configuration, currentFrame.DangerousGetPixelRowMemory(y).Span, current); - Vector256 replacement256 = Vector256.Create(replacement.X, replacement.Y, replacement.Z, replacement.W, replacement.X, replacement.Y, replacement.Z, replacement.W); + if (nextFrame != null) + { + PixelOperations.Instance.ToRgba32(configuration, nextFrame.DangerousGetPixelRowMemory(y).Span, next); + } - int size = Unsafe.SizeOf(); + ref Vector256 previousBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(previous)); + ref Vector256 currentBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(current)); + ref Vector256 nextBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(next)); + ref Vector256 resultBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); - bool hasRowDiff = false; int i = 0; uint x = 0; + bool hasRowDiff = false; int length = current.Length; int remaining = current.Length; - while (Avx2.IsSupported && remaining >= 2) + if (Avx2.IsSupported && remaining >= 8) { - Vector256 p = Unsafe.Add(ref previousBase, x); - Vector256 c = Unsafe.Add(ref currentBase, x); - - // Compare the previous and current pixels - Vector256 mask = Avx2.CompareEqual(p.AsInt32(), c.AsInt32()); - mask = Avx2.CompareEqual(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); - mask = Avx2.And(mask, Avx2.Shuffle(mask, 0b_01_00_11_10)).AsInt32(); - - Vector256 neq = Avx2.Xor(mask.AsInt64(), Vector256.AllBitsSet).AsInt32(); - int m = Avx2.MoveMask(neq.AsByte()); - if (m != 0) + Vector256 r256 = previousFrame != null ? Vector256.Create(bg.PackedValue) : Vector256.Zero; + Vector256 vmb256 = Vector256.Zero; + if (blend) { - // If is diff is found, the left side is marked by the min of previously found left side and the start position. - // The right is the max of the previously found right side and the end position. - int start = i + (BitOperations.TrailingZeroCount(m) / size); - int end = i + (2 - (BitOperations.LeadingZeroCount((uint)m) / size)); - left = Math.Min(left, start); - right = Math.Max(right, end); - hasRowDiff = true; - hasDiff = true; + vmb256 = Avx2.CompareEqual(vmb256, vmb256); } - // Replace the pixel value with the replacement if the full pixel is matched. - Vector256 r = Avx.BlendVariable(c, replacement256, mask.AsSingle()); - Unsafe.Add(ref resultBase, x) = r; - - x++; - i += 2; - remaining -= 2; + while (remaining >= 8) + { + Vector256 p = Unsafe.Add(ref previousBase, x).AsUInt32(); + Vector256 c = Unsafe.Add(ref currentBase, x).AsUInt32(); + + Vector256 eq = Avx2.CompareEqual(p, c); + Vector256 r = Avx2.BlendVariable(c, r256, Avx2.And(eq, vmb256)); + + if (nextFrame != null) + { + Vector256 n = Avx2.ShiftRightLogical(Unsafe.Add(ref nextBase, x).AsUInt32(), 24).AsInt32(); + eq = Avx2.AndNot(Avx2.CompareGreaterThan(Avx2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq); + } + + Unsafe.Add(ref resultBase, x) = r.AsByte(); + + uint msk = (uint)Avx2.MoveMask(eq.AsByte()); + msk = ~msk; + + if (msk != 0) + { + // If is diff is found, the left side is marked by the min of previously found left side and the start position. + // The right is the max of the previously found right side and the end position. + int start = i + (BitOperations.TrailingZeroCount(msk) / sizeof(uint)); + int end = i + (8 - (BitOperations.LeadingZeroCount(msk) / sizeof(uint))); + left = Math.Min(left, start); + right = Math.Max(right, end); + hasRowDiff = true; + hasDiff = true; + } + + x++; + i += 8; + remaining -= 8; + } } for (i = remaining; i > 0; i--) { x = (uint)(length - i); - Vector4 p = Unsafe.Add(ref Unsafe.As, Vector4>(ref previousBase), x); - Vector4 c = Unsafe.Add(ref Unsafe.As, Vector4>(ref currentBase), x); - ref Vector4 r = ref Unsafe.Add(ref Unsafe.As, Vector4>(ref resultBase), x); + Rgba32 p = Unsafe.Add(ref MemoryMarshal.GetReference(previous), x); + Rgba32 c = Unsafe.Add(ref MemoryMarshal.GetReference(current), x); + Rgba32 n = Unsafe.Add(ref MemoryMarshal.GetReference(next), x); + ref Rgba32 r = ref Unsafe.Add(ref MemoryMarshal.GetReference(result), x); - if (p != c) - { - r = c; + bool peq = c.Rgba == (previousFrame != null ? p.Rgba : bg.Rgba); + Rgba32 val = (blend & peq) ? replacement : c; + + peq &= nextFrame == null || (n.Rgba >> 24 >= c.Rgba >> 24); + r = val; + if (!peq) + { // If is diff is found, the left side is marked by the min of previously found left side and the diff position. // The right is the max of the previously found right side and the diff position + 1. left = Math.Min(left, (int)x); @@ -127,10 +152,6 @@ internal static class AnimationUtilities hasRowDiff = true; hasDiff = true; } - else - { - r = replacement; - } } if (hasRowDiff) @@ -143,7 +164,7 @@ internal static class AnimationUtilities bottom = y + 1; } - PixelOperations.Instance.FromVector4Destructive(configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span, PixelConversionModifiers.Scale); + PixelOperations.Instance.FromRgba32(configuration, result, resultFrame.DangerousGetPixelRowMemory(y).Span); } Rectangle bounds = Rectangle.FromLTRB( @@ -163,19 +184,6 @@ internal static class AnimationUtilities return (hasDiff, bounds); } - - public static void CopySource(ImageFrame source, ImageFrame destination, Rectangle bounds) - where TPixel : unmanaged, IPixel - { - Buffer2DRegion sourceBuffer = source.PixelBuffer.GetRegion(bounds); - Buffer2DRegion destBuffer = destination.PixelBuffer.GetRegion(bounds); - for (int y = 0; y < destBuffer.Height; y++) - { - Span sourceRow = sourceBuffer.DangerousGetRowSpan(y); - Span destRow = destBuffer.DangerousGetRowSpan(y); - sourceRow.CopyTo(destRow); - } - } } #pragma warning disable SA1201 // Elements should appear in the correct order diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 37e31f32d7..2186cc2e45 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -264,10 +264,13 @@ internal sealed class GifEncoderCore : IImageEncoderInternals hasPaletteQuantizer = true; } + ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; + this.EncodeAdditionalFrame( stream, previousFrame, currentFrame, + nextFrame, encodingFrame, useLocal, gifMetadata, @@ -311,6 +314,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals Stream stream, ImageFrame previousFrame, ImageFrame currentFrame, + ImageFrame? nextFrame, ImageFrame encodingFrame, bool useLocal, GifFrameMetadata metadata, @@ -325,7 +329,15 @@ internal sealed class GifEncoderCore : IImageEncoderInternals ImageFrame? previous = previousDisposal == GifDisposalMethod.RestoreToBackground ? null : previousFrame; // Deduplicate and quantize the frame capturing only required parts. - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(this.configuration, previous, currentFrame, encodingFrame, Vector4.Zero); + (bool difference, Rectangle bounds) = + AnimationUtilities.DeDuplicatePixels( + this.configuration, + previous, + currentFrame, + nextFrame, + encodingFrame, + Color.Transparent, + true); using IndexedImageFrame quantized = this.QuantizeAdditionalFrameAndUpdateMetadata( encodingFrame, diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 7908109e8e..932916dec2 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,7 +3,6 @@ using System.Buffers; using System.Buffers.Binary; -using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; @@ -208,21 +207,22 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable for (int i = 1; i < image.Frames.Count; i++) { - currentFrame = image.Frames[i]; - frameMetadata = GetPngFrameMetadata(currentFrame); - ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero); + currentFrame = image.Frames[i]; + ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - if (difference && previousDisposal != PngDisposalMethod.RestoreToBackground) - { - if (frameMetadata.BlendMethod == PngBlendMethod.Source) - { - // We've potentially introduced transparency within our area of interest - // so we need to overwrite the changed area with the full data. - AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); - } - } + frameMetadata = GetPngFrameMetadata(currentFrame); + bool blend = frameMetadata.BlendMethod == PngBlendMethod.Over; + + (bool difference, Rectangle bounds) = + AnimationUtilities.DeDuplicatePixels( + image.Configuration, + prev, + currentFrame, + nextFrame, + encodingFrame, + Color.Transparent, + blend); if (clearTransparency) { diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index db12d7c676..e37c1d1796 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; @@ -161,22 +160,23 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals for (int i = 1; i < image.Frames.Count; i++) { - ImageFrame currentFrame = image.Frames[i]; - frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); - ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; + ImageFrame currentFrame = image.Frames[i]; + ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero, ClampingMode.Even); - - if (difference && previousDisposal != WebpDisposalMethod.RestoreToBackground) - { - if (frameMetadata.BlendMethod == WebpBlendMethod.Source) - { - // We've potentially introduced transparency within our area of interest - // so we need to overwrite the changed area with the full data. - AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); - } - } + frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); + bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over; + + (bool difference, Rectangle bounds) = + AnimationUtilities.DeDuplicatePixels( + image.Configuration, + prev, + currentFrame, + nextFrame, + encodingFrame, + Color.Transparent, + blend, + ClampingMode.Even); using Vp8LEncoder animatedEncoder = new( this.memoryAllocator, @@ -232,21 +232,23 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals for (int i = 1; i < image.Frames.Count; i++) { + ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; ImageFrame currentFrame = image.Frames[i]; - frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); + ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - ImageFrame? prev = previousDisposal == WebpDisposalMethod.RestoreToBackground ? null : previousFrame; - (bool difference, Rectangle bounds) = AnimationUtilities.DeDuplicatePixels(image.Configuration, prev, currentFrame, encodingFrame, Vector4.Zero, ClampingMode.Even); - - if (difference && previousDisposal != WebpDisposalMethod.RestoreToBackground) - { - if (frameMetadata.BlendMethod == WebpBlendMethod.Source) - { - // We've potentially introduced transparency within our area of interest - // so we need to overwrite the changed area with the full data. - AnimationUtilities.CopySource(currentFrame, encodingFrame, bounds); - } - } + frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(currentFrame); + bool blend = frameMetadata.BlendMethod == WebpBlendMethod.Over; + + (bool difference, Rectangle bounds) = + AnimationUtilities.DeDuplicatePixels( + image.Configuration, + prev, + currentFrame, + nextFrame, + encodingFrame, + Color.Transparent, + blend, + ClampingMode.Even); using Vp8Encoder animatedEncoder = new( this.memoryAllocator, diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 5430494a88..851c792170 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -480,6 +480,7 @@ public static class TestImages public const string LargeComment = "Gif/large_comment.gif"; public const string GlobalQuantizationTest = "Gif/GlobalQuantizationTest.gif"; public const string MixedDisposal = "Gif/mixed-disposal.gif"; + public const string M4nb = "Gif/m4nb.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -511,6 +512,7 @@ public static class TestImages public static readonly string[] Animated = { + M4nb, Giphy, Cheers, Kumin, diff --git a/tests/Images/Input/Gif/m4nb.gif b/tests/Images/Input/Gif/m4nb.gif new file mode 100644 index 0000000000..0c921b2afb --- /dev/null +++ b/tests/Images/Input/Gif/m4nb.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b5b495caf1eb1f1cf7b15a1998faa33a6f4a49999e5edd435d4ff91265ff1ce5 +size 2100 From 6bfabe9d547dbda90d633155d460b6044d464e9b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 28 Nov 2023 22:59:38 +1000 Subject: [PATCH 061/219] Reduce memory pressure on gif decoder tests --- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 4 ++-- .../Decode_VerifyRootFrameAndFrameCount_Rgba32_cheers.png | 3 --- ...tFrameAndFrameCount_Rgba32_issue403_baddescriptorwidth.png | 3 --- .../Decode_VerifyRootFrameAndFrameCount_Rgba32_m4nb.png | 3 +++ ...ode_VerifyRootFrameAndFrameCount_Rgba32_mixed-disposal.png | 3 +++ 5 files changed, 8 insertions(+), 8 deletions(-) delete mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_cheers.png delete mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_issue403_baddescriptorwidth.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_m4nb.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_mixed-disposal.png diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 8b23927418..a99d3c65bf 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -101,9 +101,9 @@ public class GifDecoderTests } [Theory] - [WithFile(TestImages.Gif.Cheers, PixelTypes.Rgba32, 93)] + [WithFile(TestImages.Gif.M4nb, PixelTypes.Rgba32, 5)] [WithFile(TestImages.Gif.Rings, PixelTypes.Rgba32, 1)] - [WithFile(TestImages.Gif.Issues.BadDescriptorWidth, PixelTypes.Rgba32, 36)] + [WithFile(TestImages.Gif.MixedDisposal, PixelTypes.Rgba32, 11)] public void Decode_VerifyRootFrameAndFrameCount(TestImageProvider provider, int expectedFrameCount) where TPixel : unmanaged, IPixel { diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_cheers.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_cheers.png deleted file mode 100644 index d5be7b0b25..0000000000 --- a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_cheers.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:b199a36f9e682a54c5d7c67f3403bba174b37e1a7a8412481f66c6d5eb0349e9 -size 27679 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_issue403_baddescriptorwidth.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_issue403_baddescriptorwidth.png deleted file mode 100644 index 5bd551cb16..0000000000 --- a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_issue403_baddescriptorwidth.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:4bedcf1a0ca0281dd5531d96c74e19c5d5fd379d6e2acb899077299917215705 -size 1013 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_m4nb.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_m4nb.png new file mode 100644 index 0000000000..abe2828ec7 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_m4nb.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:04239ee46f0276ba52566bcb2407f4a6fcee35b3f51a6182394f851e2d8df3fc +size 277 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_mixed-disposal.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_mixed-disposal.png new file mode 100644 index 0000000000..c30d822c18 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Decode_VerifyRootFrameAndFrameCount_Rgba32_mixed-disposal.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0b654f948a26d256ff9e28ada399465bd6a4205aedaf93ea7cdffb70483535ef +size 2216 From 9677be02ade3194003b4542708f4f9a57c37d42f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 28 Nov 2023 23:14:31 +1000 Subject: [PATCH 062/219] More memory pressure reductions --- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index a99d3c65bf..5aec1f814b 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -212,7 +212,7 @@ public class GifDecoderTests public void Issue405_BadApplicationExtensionBlockLength(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(); + using Image image = provider.GetImage(GifDecoder.Instance, new() { MaxFrames = 1 }); image.DebugSave(provider); image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); @@ -224,7 +224,7 @@ public class GifDecoderTests public void Issue1668_InvalidColorIndex(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(); + using Image image = provider.GetImage(GifDecoder.Instance, new() { MaxFrames = 1 }); image.DebugSave(provider); image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); @@ -273,7 +273,7 @@ public class GifDecoderTests public void Issue1962(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(); + using Image image = provider.GetImage(GifDecoder.Instance, new() { MaxFrames = 1 }); image.DebugSave(provider); image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); @@ -285,7 +285,7 @@ public class GifDecoderTests public void Issue2012EmptyXmp(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(); + using Image image = provider.GetImage(GifDecoder.Instance, new() { MaxFrames = 1 }); image.DebugSave(provider); image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); From 35d55b5da350a31b40866f8b14c58080a000d3b4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 28 Nov 2023 23:28:24 +1000 Subject: [PATCH 063/219] More memory pressure reduction --- tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 5aec1f814b..6399e1193e 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -133,7 +133,6 @@ public class GifDecoderTests } [Theory] - [InlineData(TestImages.Gif.Cheers, 8)] [InlineData(TestImages.Gif.Giphy, 8)] [InlineData(TestImages.Gif.Rings, 8)] [InlineData(TestImages.Gif.Trans, 8)] @@ -194,7 +193,7 @@ public class GifDecoderTests } } - // https://github.com/SixLabors/ImageSharp/issues/1503 + // https://github.com/SixLabors/ImageSharp/issues/1530 [Theory] [WithFile(TestImages.Gif.Issues.Issue1530, PixelTypes.Rgba32)] public void Issue1530_BadDescriptorDimensions(TestImageProvider provider) From e35e9a8d89d78067fe855e98c0b0bb5763435615 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 10:00:57 +1000 Subject: [PATCH 064/219] Reduce memory usage in pixel map --- .../Processors/Quantization/EuclideanPixelMap{TPixel}.cs | 4 ++-- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 2 +- .../Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp | 2 +- .../Encode_8BitColor_WithWuQuantizer_rgb32.bmp | 2 +- .../ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png | 4 ++-- .../ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png | 4 ++-- ...Filter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png | 4 ++-- ...nFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png | 4 ++-- ...Filter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png | 4 ++-- ...er_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png | 4 ++-- ...ffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png | 4 ++-- .../DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png | 4 ++-- ...nFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png | 4 ++-- ...lter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png | 4 ++-- ...iffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png | 4 ++-- ...iffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png | 4 ++-- ...usionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png | 4 ++-- ...onFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png | 4 ++-- ...DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png | 4 ++-- ..._WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png | 4 ++-- ...ter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png | 4 ++-- ...WithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png | 4 ++-- ...hAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png | 4 ++-- ...r_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png | 4 ++-- ...r_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png | 4 ++-- ...orksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png | 4 ++-- ...sWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png | 4 ++-- ...er_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png | 4 ++-- .../DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png | 4 ++-- .../DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png | 4 ++-- .../DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png | 4 ++-- .../DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png | 4 ++-- .../DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png | 4 ++-- ...ter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png | 4 ++-- ...ilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png | 4 ++-- ...ilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png | 4 ++-- ...ilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png | 4 ++-- ...ter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png | 4 ++-- ...Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png | 4 ++-- ...pplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png | 4 ++-- .../ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png | 4 ++-- ...lyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png | 4 ++-- ...tizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png | 4 ++-- ...uantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png | 4 ++-- ...zationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png | 4 ++-- ...ntizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png | 4 ++-- ...QuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png | 4 ++-- ...izationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png | 4 ++-- .../ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png | 4 ++-- .../ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png | 4 ++-- .../ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png | 4 ++-- ...ionInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png | 4 ++-- ...zationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png | 4 ++-- ...nInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png | 4 ++-- ..._CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png | 4 ++-- ...Box_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png | 4 ++-- ...alliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png | 4 ++-- ...x_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png | 4 ++-- ...nBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png | 4 ++-- ...CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png | 4 ++-- ...izationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png | 4 ++-- ...antizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png | 4 ++-- ...ationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png | 4 ++-- ...hDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png | 4 ++-- ...thDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png | 4 ++-- ...hDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png | 4 ++-- ...WithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png | 4 ++-- ...WithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png | 4 ++-- ...itheringScale_david_OctreeQuantizer_OrderedDither_0.25.png | 4 ++-- ...DitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png | 4 ++-- ...itheringScale_david_OctreeQuantizer_OrderedDither_0.75.png | 4 ++-- ...thDitheringScale_david_OctreeQuantizer_OrderedDither_0.png | 4 ++-- ...thDitheringScale_david_OctreeQuantizer_OrderedDither_1.png | 4 ++-- ...ngScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png | 4 ++-- ...ingScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png | 4 ++-- ...ngScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png | 4 ++-- ...eringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png | 4 ++-- ...eringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png | 4 ++-- ...Scale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png | 4 ++-- ...gScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png | 4 ++-- ...Scale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png | 4 ++-- ...ingScale_david_WebSafePaletteQuantizer_OrderedDither_0.png | 4 ++-- ...ingScale_david_WebSafePaletteQuantizer_OrderedDither_1.png | 4 ++-- ...ingScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png | 4 ++-- ...ringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png | 4 ++-- ...ingScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png | 4 ++-- ...heringScale_david_WernerPaletteQuantizer_ErrorDither_0.png | 4 ++-- ...heringScale_david_WernerPaletteQuantizer_ErrorDither_1.png | 4 ++-- ...gScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png | 4 ++-- ...ngScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png | 4 ++-- ...gScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png | 4 ++-- ...ringScale_david_WernerPaletteQuantizer_OrderedDither_0.png | 4 ++-- ...ringScale_david_WernerPaletteQuantizer_OrderedDither_1.png | 4 ++-- ...nWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png | 4 ++-- ...onWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png | 4 ++-- ...nWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png | 4 ++-- ...tionWithDitheringScale_david_WuQuantizer_ErrorDither_0.png | 4 ++-- ...tionWithDitheringScale_david_WuQuantizer_ErrorDither_1.png | 4 ++-- ...ithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png | 4 ++-- ...WithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png | 4 ++-- ...ithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png | 4 ++-- ...onWithDitheringScale_david_WuQuantizer_OrderedDither_0.png | 4 ++-- ...onWithDitheringScale_david_WuQuantizer_OrderedDither_1.png | 4 ++-- .../ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png | 4 ++-- .../ApplyQuantization_Bike_OctreeQuantizer_NoDither.png | 4 ++-- .../ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png | 4 ++-- ...yQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png | 4 ++-- ...pplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png | 4 ++-- ...uantization_Bike_WebSafePaletteQuantizer_OrderedDither.png | 4 ++-- ...lyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png | 4 ++-- ...ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png | 4 ++-- ...Quantization_Bike_WernerPaletteQuantizer_OrderedDither.png | 4 ++-- .../ApplyQuantization_Bike_WuQuantizer_ErrorDither.png | 4 ++-- .../ApplyQuantization_Bike_WuQuantizer_NoDither.png | 4 ++-- .../ApplyQuantization_Bike_WuQuantizer_OrderedDither.png | 4 ++-- ...tization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png | 4 ++-- ...uantization_CalliphoraPartial_OctreeQuantizer_NoDither.png | 4 ++-- ...zation_CalliphoraPartial_OctreeQuantizer_OrderedDither.png | 4 ++-- ..._CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png | 4 ++-- ...ion_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png | 4 ++-- ...alliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png | 4 ++-- ...n_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png | 4 ++-- ...tion_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png | 4 ++-- ...CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png | 4 ++-- ...Quantization_CalliphoraPartial_WuQuantizer_ErrorDither.png | 4 ++-- ...plyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png | 4 ++-- ...antization_CalliphoraPartial_WuQuantizer_OrderedDither.png | 4 ++-- 127 files changed, 251 insertions(+), 251 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 3c7d576709..72148374aa 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -184,14 +184,14 @@ internal sealed class EuclideanPixelMap : IDisposable /// The granularity of the cache has been determined based upon the current /// suite of test images and provides the lowest possible memory usage while /// providing enough match accuracy. - /// Entry count is currently limited to 4601025 entries (8MB). + /// Entry count is currently limited to 2335905 entries (4MB). /// /// private unsafe struct ColorDistanceCache : IDisposable { private const int IndexRBits = 5; private const int IndexGBits = 5; - private const int IndexBBits = 6; + private const int IndexBBits = 5; private const int IndexABits = 6; private const int IndexRCount = (1 << IndexRBits) + 1; private const int IndexGCount = (1 << IndexGBits) + 1; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 6679a765f5..c81b7eb6cd 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -499,7 +499,7 @@ public partial class PngEncoderTests // TODO: Find a better way to compare. // The image has been visually checked but the quantization pattern used in the png encoder // means we cannot use an exact comparison nor replicate using the quantizing processor. - ImageComparer.TolerantPercentage(0.12f).VerifySimilarity(output, image); + ImageComparer.TolerantPercentage(0.46f).VerifySimilarity(output, image); GifMetadata gif = image.Metadata.GetGifMetadata(); PngMetadata png = output.Metadata.GetPngMetadata(); diff --git a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp index d484eace0f..2b8e05b070 100644 --- a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp +++ b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithOctreeQuantizer_rgb32.bmp @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:23a9d9233314ec08bd3e464f245e69d96566cbb12d2dba36c69bba483d6ba6b8 +oid sha256:11375b15df083d98335f4a4baf0717e7fdd6b21ab2132a6815cadc787ac17e7d size 9270 diff --git a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp index 6896c4fa6a..f7eb06c558 100644 --- a/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp +++ b/tests/Images/External/ReferenceOutput/BmpEncoderTests/Encode_8BitColor_WithWuQuantizer_rgb32.bmp @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3052831cb18fecc26f54e29dfe19b538d2e0d3c104ddd7ec5bc8e0adcf56693c +oid sha256:e063e97cd8a000de6830adcc3961a7dc41785d40cd4d83af10ca38d96e071362 size 9270 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png index 39bb7e52b9..de42d1bfc2 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDiffusionFilterInBox_Rgba32_CalliphoraPartial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e89597ab9aa006d026a560d1482350739bd93604d9c6726f6730d782c017a0a3 -size 273049 +oid sha256:681b0e36298cb702683fb9ffb2a82f7dfd9080b268db19a03f413809f69d0e07 +size 273269 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png index 133112867c..43e414da6d 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/ApplyDitherFilterInBox_Rgba32_CalliphoraPartial.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:59d331efd9e6d926eaf90bed1f76b3ba55b2a42d2f83fc512a985cdea97781ec -size 271152 +oid sha256:a899a84c6af24bfad89f9fde75957c7a979d65bcf096ab667cb976efd71cb560 +size 271171 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png index cac3b9c421..d8ececb4cd 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Bgra32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 -size 727 +oid sha256:f7c19df70d24948e1a36299705bb030715cf0d01b453d390989d472c0999d46a +size 728 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png index cac3b9c421..d8ececb4cd 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgb24_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 -size 727 +oid sha256:f7c19df70d24948e1a36299705bb030715cf0d01b453d390989d472c0999d46a +size 728 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png index cac3b9c421..d8ececb4cd 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_Rgba32_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3cee43ebaefd94bcd993b8548f734a0a44b948a532263b8d2ee41b0cd42ab7a9 -size 727 +oid sha256:f7c19df70d24948e1a36299705bb030715cf0d01b453d390989d472c0999d46a +size 728 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png index 4a3a1e874b..5da96d59d2 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_ShouldNotDependOnSinglePixelType_RgbaVector_filter0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f6df6c76c0f3795c439147fd49d658e52fae5c24a071ee0f4fed7aa096d87d1 -size 719 +oid sha256:0e7ece9d70c4fe0771abd43e4dbb33fb95f474ca56633dcb821022ee44e746d4 +size 728 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png index 5db7bd5ef3..1656b2e9cb 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Atkinson.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c419d6b6cb589f95bff06514e3a5da37d7b5704aa3f9e6f4365fe5e00c6d81d1 -size 50670 +oid sha256:38597c6144d61960d25c74d7a465b1cdf69b7c0804a6dec68128a6c953258313 +size 52688 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png index b2c8578011..c6016ae358 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Burks.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:90c337c38076fb597ecde87e0e8b5b95c369a90a99e64c5add3b31fc778cb52d -size 61178 +oid sha256:5f9191c71eea1f73aa4c55397ca26f240615c9c4a7fff9a05e6f2e046b5e4d8b +size 62323 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png index 7ceb6114ad..40243937d3 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_FloydSteinberg.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ce4b978b800820275635ae8da59212661c74a1b6ba9050ebf052c87315aedef -size 62107 +oid sha256:b63810145832db459bb7a6b37a028a7b778f6b6b4e6eae00e50e6e21c5a06086 +size 62199 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png index 9f2a2482aa..83f9e067db 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_JarvisJudiceNinke.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e44a87274d4f4fc5f1a0a849f27108ff8b98410f5d1e5e328236a9c79b9af51b -size 56175 +oid sha256:a67c14ef99a943706f050ff1ea0ef101429292d52bc14ed4610f8338736ff87e +size 56800 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png index a8a0eda5e1..22e4f4b6d6 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:542285d1c2a375f64680173ca2736399d061009413e8aacf62f785425357f868 -size 58538 +oid sha256:623dd82d372ba517b0d3357d06cffaf105d407a9090cbcbc6a76ae944ab33d67 +size 59468 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png index 58a5909c06..838863c158 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Sierra3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b4aa18018421bda728ec9adab4eff235d4f4c683a0bb5328dab386833685ab35 -size 57616 +oid sha256:8edceef8e12c4f3d194523437045c5cf4e80c7bb95ff75f38c1f38a21872e3d0 +size 59376 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png index 847aab49cd..60513e1992 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_SierraLite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ec9d5fe07a99a995e889870ac4f6d264360adf1dbc5cb656d5657e096fe7f393 -size 61838 +oid sha256:b1d7019e8cb170ae67496f8250446c4f6b6217378658408c3d51a95c49a4c3bc +size 63287 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png index d8cb185c9e..0d1b34d8ce 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_StevensonArce.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b2dd1df6e5fb97b5fdeab6450713432ee1e0a318953b11ab25f4618bde369792 -size 54658 +oid sha256:d7c03ede7ab3bd4e57e6a63e53e2e8c771e938fdc7d5dfe5c9339a2c9907c9cf +size 55550 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png index 6df5a227bf..f8c998ecbd 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_Bike_Stucki.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ba66ef358ebcec36932e6d2874827846b31585fcbc0683e26c548fc3706e27e3 -size 57294 +oid sha256:79b690b91223d1fe7ddf1b8826b4474b89644822bc8aa9adee3cf819bc095b4c +size 60979 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png index c4a20b45a3..cc2327b23f 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Atkinson.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9f777e6d61a882da066a00b9d268be5fdbf49bdbccb568eb5bb3d959fe9f4fb0 -size 57454 +oid sha256:7e22401dddf6552cd91517c1cdd142d3b9a66a7ad5c80d2e52ae07a7f583708e +size 57657 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png index 0c52494844..e3ae6508e1 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Burks.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2b00d60902d54f911a9b4ab9be225ab589073b9f0efe06019895a75e487eadec -size 59415 +oid sha256:819a0ce38e27e2adfa454d8c5ad5b24e818bf8954c9f2406f608dcecf506c2c4 +size 59838 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png index 0364487787..2b897a5d6d 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_FloydSteinberg.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ded9cb4986e620f5fc11486ccdf81934dff7b3cea7db7e292929d339ecc21714 -size 60116 +oid sha256:007ac609ec61b39c7bdd04bc87a698f5cdc76eadd834c1457f41eb9c135c3f7b +size 60688 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png index 587929f1fa..10ba90ae86 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_JarvisJudiceNinke.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:1518a2c1840a8d88767a45c7ba08b904ea471c7422fbb5f2b623f1f219992f83 -size 58479 +oid sha256:46892c07e9a93f1df71f0e38b331a437fb9b7c52d8f40cf62780cb6bd35d3b13 +size 58963 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png index 0cccb2c775..9608289e84 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:01c6000407f5302a5dd27a88053f795cdb101c791f92e983e6859792ef8a0935 -size 58879 +oid sha256:1b83345ca3de8d1fc0fbb5d8e68329b94ad79fc29b9f10a1392a97ffe9a0733e +size 58985 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png index 7150bcc1f0..79d2c5eb14 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Sierra3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:11438d8eef23ae6ff5b7d37f0ccc9b6bfe744abb2dc95785a5769c306e51d11b -size 58908 +oid sha256:c775a5b19ba09e1b335389e0dc12cb0c3feaff6072e904da750a676fcd6b07dc +size 59202 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png index d1919cbd1d..8d3cf1a564 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_SierraLite.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:57584582f914c0c059899f9241de006526a14081093b647972c363b00de62a57 -size 60492 +oid sha256:6c88740c0553829eaa42ca751b34cc456623a84ccdff4020949a06ef4b4802d1 +size 61137 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png index 6778314d56..a146f8f668 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_StevensonArce.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:adfc7192b03c29addbc9c19e9eefc5c122d35d3d0fae7dfa65d3390ee5f60502 -size 57887 +oid sha256:0a4a404b0767faac952435f768867cf7bf053848e1e3ef121624f136658a107c +size 58386 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png index 5c8c2f3cc5..edec46a92a 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DiffusionFilter_WorksWithAllErrorDiffusers_CalliphoraPartial_Stucki.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9735370ed168043d1fd176a258f08fcd705dcefc1d5e6841d012e843ec34d7a9 -size 58485 +oid sha256:8cc216ed952216d203836dc559234216614f1ed059651677cc0ea714010bd932 +size 58855 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png index cb4ce61385..e899ffb42a 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer16x16.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f844bf243df10178cdc8bd0d49fa8e7722476373c5b2cbc494bdc53eaa7a116 -size 44133 +oid sha256:ca70bb0200776efd00c4ef7596d4e1f2f5fbc68e447b395b25ef2b3c732e5156 +size 44189 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png index 7669d9686e..543640c2e8 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer2x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b80161aa7723ac8804a2679fbb1fc8327961166475e1a3567ee7bf1f61b43307 -size 41530 +oid sha256:8474b847b7d4a8f3e5c9793ca257ce46efcf49c473c731a9ca9c759851410b94 +size 43066 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png index cc825e03f7..fec3c9b2b3 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer4x4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:69e745d55bb37c75c5651713648fb9d2d761b8790b86b67e9a553a7ae6328f0a -size 43625 +oid sha256:20e80e7d9e68fd85bfbc63c61953327354b0634000ec142e01a42618995fd14c +size 44391 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png index 9710298a3d..68a95a0540 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Bayer8x8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2a534bc0862e0d7325e9d6bbdf1c73ddc356bd621dfdc64a9c0c04399a93e00 -size 43807 +oid sha256:8af98bfcc5edef3f3ff33ee8f76f33ce2906a6677167e2b29e1dbe63b00a78d8 +size 44202 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png index e6fc9aa0fe..d67f02dca5 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_Bike_Ordered3x3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4ba2d0740f6d614725125c393ed8cf19e0dc648a82b114de5b8531a97e828351 -size 43868 +oid sha256:b149ebbd550808ae46ff05b5ddcdb1fc0eb6ae0eacbe048e9a1ff24368d8f64d +size 45003 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png index 3251f0466d..4175cf40b7 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer16x16.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a980061a57ac57351b4ccedb34f915319373759753cf2d28fb604a968b87fb2f -size 50640 +oid sha256:9316cbbcb137ae6ff31646f6a5ba1d0aec100db4512509f7684187e74d16a111 +size 51074 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png index 7bf58cd3ef..11d916bdc3 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer2x2.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4b64630a74a435fde316a2d6be140ef54b04fecbf5fa76e31014d92c9cd925db -size 52298 +oid sha256:08c39a43993deadebab21f1d3504027b5910a52adc437c167d77d62e5f5db46e +size 52762 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png index c7e3a05892..a4f91b3301 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer4x4.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3535fa1a240cc7c11e9bb233333894f8782ec67ac36708c8ee3baf905c2d3f65 -size 51268 +oid sha256:0c9c47fa755d603f8c148011511ee91f32444e0d94367f9db57593e3bf30f2e0 +size 51808 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png index 687cd1dbca..ac56fa9236 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Bayer8x8.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2d47f277bc904ed8c3b3bbfe636b647884511de39661bfd34cdcb2abe9f6a13 -size 50818 +oid sha256:6d2289ed4fa0c679f0f120d260fec8ab40b1599043cc0a1fbebc6b67e238ff87 +size 51428 diff --git a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png index dd21dc76da..9a7c7b4611 100644 --- a/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png +++ b/tests/Images/External/ReferenceOutput/DitherTests/DitherFilter_WorksWithAllDitherers_CalliphoraPartial_Ordered3x3.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ed86ea3844a13de5247bcb409c70ca4a8051cb18b6a3c298a5665f4573f89490 -size 51756 +oid sha256:366e84ab8587735455798651096d2af5f965fc325f4852dc68356e94600598b1 +size 52176 diff --git a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png index 6ea363a346..4c78303750 100644 --- a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png +++ b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2469_Quantized_Encode_Artifacts_Rgba32_issue_2469.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:968a3cfdec62a89823e711f7ed15e3c456a8e44b8f9d46268dd312693e04be00 -size 1028911 +oid sha256:1af50619f835b4470afac4553445176c121c3c9fa838dff937dcc56ae37941c3 +size 945821 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png index 939897ba91..4948c7adee 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:62b08eae3bbcc99c2dace7156dae8e37786416e1e428455417b3efc7cdcbd56a -size 240453 +oid sha256:a51d04953c1c82d99884af62912d2271108c6bc62f18d4b32d0b5290c01fa7f7 +size 247462 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png index 5afed57042..d993923d48 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f240153a429da26fbe2ffcbce71ceeae47225c261002c242c34b2747823d0f9a -size 231151 +oid sha256:9f165908729d723818b6c5843bd75298d987448e2cd4278dfe3f388a62025add +size 238396 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png index 0a026b2179..223d3bc012 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7700134ca070ccef3f027b70534a811e4a388d05b421ca91d9176d84310ddfc0 -size 237380 +oid sha256:34eaa0696da00838e591b2c48e7797641521f7f3feb01abbd774591c4dd6f200 +size 265546 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png index 9771816664..922c2bf9b2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e46eddb5225c37cfe20a4d94af0eabd1def78eb379a17d9cdae5fae0866d2bb -size 208360 +oid sha256:4f1462733e02d499b0d8c61ab835a27c7fee560fdc7fc521d20ec09bb4ccc80f +size 216030 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png index 9771816664..922c2bf9b2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4e46eddb5225c37cfe20a4d94af0eabd1def78eb379a17d9cdae5fae0866d2bb -size 208360 +oid sha256:4f1462733e02d499b0d8c61ab835a27c7fee560fdc7fc521d20ec09bb4ccc80f +size 216030 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png index cce6455851..29c93d14e2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:344efea18d09c8c9b23d7c06a8e865c271dc6acdc9330b589d9ebe15b48c285f -size 215670 +oid sha256:7e6d91a3ec4f974af675dc360fd5fd623ec8773cdbc88c0a3a6506880838718a +size 226727 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png index a5433fa6ea..dbfab2b508 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c32da9b861ac38306d1bfcae6384e4cdf449cfdb9de1fee3fdb6975e4096aea6 -size 212659 +oid sha256:c68eba122814b5470e5f2e03e34190ff79e84e4b431ad8227355ce7ffcd4a6a7 +size 220192 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png index a5433fa6ea..dbfab2b508 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c32da9b861ac38306d1bfcae6384e4cdf449cfdb9de1fee3fdb6975e4096aea6 -size 212659 +oid sha256:c68eba122814b5470e5f2e03e34190ff79e84e4b431ad8227355ce7ffcd4a6a7 +size 220192 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png index 284b8ad041..86655af42b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:60fcd8cf74e595b9f5add7ef6924e4ed801f3835b7d2873bbc79e0b61b98bb0f -size 218566 +oid sha256:6dbd3189b559941f91dd6e0aa15b34a3e5081477400678c2396c6a66d398876f +size 230883 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png index 430f98d007..82d5e5d592 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:3a650e180ee2f073f5d06ef343f5d14cde568777a21d8f419dae6c23f36bfb66 -size 255237 +oid sha256:f4df5b1bc2c291ec1cf599580d198b447278412576ab998e099cc21110e82b3d +size 263152 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png index f75e878311..d8a1178adc 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:934c4a8fd38d2d360dd1b69627043895975ee33ed63e2b1e514b8c6f8451c3f0 -size 253854 +oid sha256:df63a3d12e2998d5242b64169ac86e3df7ab4be585a80daddc3e3888dfcb7095 +size 262298 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png index 558f8a545c..76946ee06f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_Bike_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:38a6c8caeef772c51508954483810ecf4aa13168a8ec33af266cde028ee19f75 -size 249584 +oid sha256:457a0b4e27a09440ff4e13792b68fb5a9da82b7ce6129ea15a5ea8dcd99bd522 +size 274300 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png index fb9b5513c5..ebb9ff6b00 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:649e8a71ba3328af6a48a0afe8747433bce459bed50ba5f4108343265f07cdf2 -size 314905 +oid sha256:f414473561bfa792c2e6342ff5e5dddffbdec5286932781b11a093803593b52a +size 313787 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png index 77d1cc1153..7e3080562c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d484a8d20c288de3f30b6c8ea2cecb6893d618d96e8a9079c0003ee49c798967 -size 303608 +oid sha256:0203ecb9e4665e7c3992b7da4777c6d35b539790506fc9ca2acbcbc2bdb5db18 +size 303979 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png index 34ba72d102..5626fa1b83 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b935deeff7a6f9be835f1975513b0063090d52e5d4178da1ce8575909729164 -size 320831 +oid sha256:62cdce27fc46a38a16995df8ed1501f65091d69315288479b1d613b1d87c8239 +size 321123 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png index c575778e08..0205626738 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c14e3f64a9fa9487c4828bc931338525663177828d65f31928b1acf6f5c1d3a7 -size 269542 +oid sha256:3a2aae04edebcaca9b95f30963201794887fa0eac954b64c68bfe529b14fa9be +size 269397 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png index c575778e08..0205626738 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:c14e3f64a9fa9487c4828bc931338525663177828d65f31928b1acf6f5c1d3a7 -size 269542 +oid sha256:3a2aae04edebcaca9b95f30963201794887fa0eac954b64c68bfe529b14fa9be +size 269397 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png index 02f91294f4..68d91fc437 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fc2c4df81110029eeaf07419c6a5a823faba757aacf776241ad3171370f70338 -size 271393 +oid sha256:2f3e9a338a5ae37c88ce0c348e0b655429220da051db3352779c277bb2dcb441 +size 270622 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png index c6f8957eec..324bd92539 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4812a323ca35208e55faf476d342202b320a302df9475f40f8d96161e09ae7ea -size 284361 +oid sha256:752760327cc1416c171a920f1e0e95e34eae6d78bd0c7393a3be427bf3c8e55c +size 284481 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png index c6f8957eec..324bd92539 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4812a323ca35208e55faf476d342202b320a302df9475f40f8d96161e09ae7ea -size 284361 +oid sha256:752760327cc1416c171a920f1e0e95e34eae6d78bd0c7393a3be427bf3c8e55c +size 284481 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png index 13974a84c0..52bf2a163f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5022fb7d43ec6885efcd6e7513ad92019f28febb91e7e2b61c421bf96cfbb76c -size 285270 +oid sha256:293459538454e07bc9ea1e9df1fa5b0eb986fde7de42f6c25b43e4c8859bd28a +size 285370 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png index 7d07b09e14..05be1395ab 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb153e0e3c50cc038f8ab215646dd2a1739e748fa4a7a04ef34ea2f6d8e0c22a -size 318803 +oid sha256:90a2b7b3872c6eb1f1f039558d9f6ace92891c86951c801da01ad55b055fd670 +size 316544 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png index 9342757f60..d94d57759f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0e09d63aaf5365a1f4ac44beef9f203c4217a7e158703d44b2b1007c413b1f0c -size 318179 +oid sha256:ff094e6bafe81e818bcbac69018dcfe29366389dfca0d63d8e05ef42896ffe1d +size 317309 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png index 5a9662e032..e016e3de69 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationInBox_CalliphoraPartial_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:563e9bf52b4ac7be22bc15e6aaf8b39e508eb7e31cb90986fe559ac88ba40829 -size 324538 +oid sha256:ee0778aac671365dd0afae06cdcf8f36243bd9815f684b975f83e297bb694e63 +size 323979 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png index dae4b4e140..82b965123d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:4bed69d43856ebd4b1af4055f8d3aacabd50c361a4e1e1f9cad080d799d6b744 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png index dae4b4e140..571b0db4b9 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:4c8c8393708002f06f9d8ed1ff8979db820035585c08b66ae463d94724fa64d3 +size 14330 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png index dae4b4e140..a1b3da6816 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:fda13875f4c762a95001426487cc04c9add39821eb793168fdbe5cc18e705643 +size 14566 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png index dae4b4e140..82b965123d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:4bed69d43856ebd4b1af4055f8d3aacabd50c361a4e1e1f9cad080d799d6b744 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png index dae4b4e140..e0fc792026 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:cb826afb127fe4175e6e47253b8a8313b9d10aee193c316731f34e5d327a2591 +size 14580 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png index 3abeb03160..491847e491 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:14dfcd85d0331448c1e3ff447e7e789ad4fc24618b6a9c5d05468bdd6a2f2209 -size 20804 +oid sha256:37018ecc499651833208d846a0f446db94cc11eae002ab6e7ce45b3e7c09e86c +size 17734 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png index 3102144a14..013bb4a3b7 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8e7df6174aad752e0f3846eeef5efc4bfc70b80e3622a54eba59f6dcd4673d87 -size 21802 +oid sha256:c2f9ed902882f58704b22460bc64a7b27bc6f47fc2c822ee09f52345cc0d6ebf +size 19255 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png index f5c07ac7a7..31fd7a5445 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:95c739dd75b7be9dea10c12dd69ea60095ac617de491a2ba8063c86cd1bd9aa3 -size 22060 +oid sha256:aad3f26f2939f3679afa2b6165db29885fff40bbb1d171d5ffecc7861b5fac31 +size 19654 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png index dae4b4e140..82b965123d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d96528a2950fb583ff1a1c00e7e13861fc582bd62b72deccaafb73f2cdd15b10 -size 20936 +oid sha256:4bed69d43856ebd4b1af4055f8d3aacabd50c361a4e1e1f9cad080d799d6b744 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png index e1bc766fbf..e2a05b9bd5 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_OctreeQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:f49ea178ca76bd1b2165b0b700a558433d27e22b07b3b35be3fdf3a1868d7ad6 -size 22371 +oid sha256:6d21029fa22dbe72cdc60b90c758cb9becd9fce03a33580d9466c1aedd323c1c +size 20000 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png index dc3d45fa1d..9850675bed 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7bf316a54f0add7d92287fddc9cc3744d4be1a7ba7c6881d83d3f45356d2c53e -size 8627 +oid sha256:ea836214840a5da2b89dad3cd9e916413d3f9e21f9b855dc8161faa3544edcfc +size 9266 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png index 6f49f27154..f3278c3d2f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:97c36988a937893cf106b7b7986fff32d0d90c882ed292010fc1172b1a149d22 -size 9388 +oid sha256:346c9e4239d917614525a99f7ae58ed0c0a22dc09d639f3a54dad1975e75ec44 +size 8833 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png index 3498290b81..77821255bb 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5e167ecea77962fa0b8376f1217cbba64c90c77e67213b229fba1c6122d2bc06 -size 11011 +oid sha256:717fe46156f3d144f31cfce066dd13532ee8721d7d3a7b8c8425c646f411e8a5 +size 11099 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png index 0f00a00f84..0615793d57 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b7fd78e11b8de40f646218597ec1ebccddbca7a6d901e5c87848ae1d9e0de361 -size 8390 +oid sha256:9e01c7276f1c4e905b1d8f4c84259f1047c0949f7a6a81f43a790bd1bd3201e3 +size 7932 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png index 93f1ca2343..c43b5836ec 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:45f3bf5ae0e8061811eebd3328f1d8f7d54dc7b213f6324148c36292509a8ee5 -size 12761 +oid sha256:ae18d22edc011d576d6a1e9545bc52084ca0bed55a6ce19d391d2a5f97b1843c +size 11763 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png index 2b611ace6f..e54740610c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36b1193c16c585918655bae2d98e4105b92cfab66ad903995f2af6b316e8b4a4 -size 9060 +oid sha256:74b3f36e3fbac940d1f3bf90089b6b40234aa2ce3570b094534a4448c1d98aec +size 8875 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png index 44f7171246..b08ba5be19 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:71d5c7b4addc49a13e0adb60dc53b463845957ea5df490cd476f011b6770373e -size 9633 +oid sha256:80e60c42fa11e973e1c865ed93448d3af0503e32d7b119bfe7162738efe691db +size 9086 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png index 67fcc5bf6c..692c119e4a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8f0e458b747377aad809e48fdf6d7af69b1e523e1728d2367615bb7ce90c2680 -size 9733 +oid sha256:fd5a9c76ee332603877624e219d84f85fe159389e7f9e72d1fb6177289dd1fb7 +size 9777 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png index 0d4f8c0f93..0615793d57 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:08e2b6d31c842366175508fbe74c8ba546d0fa88f366ebb27279e38939b3bfa8 -size 8375 +oid sha256:9e01c7276f1c4e905b1d8f4c84259f1047c0949f7a6a81f43a790bd1bd3201e3 +size 7932 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png index 7e124931c8..17a810448e 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WebSafePaletteQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a7052b23b8d91947ba1f869f13ff99136096805e889558a741ce8e5eac3ece63 -size 9965 +oid sha256:240743d5f742b872c0f66f4033ad065402372605a76cda23f4c506d254a9d127 +size 9791 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png index a54b4088b6..10b511a1a3 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5d5d5023535689657840dbf63d6343f4d1070cf5ec853586447eb8465da9640a -size 11444 +oid sha256:074842dcbdf60690f41da31e12c290045d05ab6dc587f3f5ba29c9496871391c +size 11209 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png index 7b0ab347de..1ed81c0d0a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0f9ffc543dd312b3ca9d00f5444be214edfd78dbfb1a740556da3872b33623bf -size 12062 +oid sha256:29e1ff6d454efca61852a88946e25dcf29708230bfc47c2625c4d1b2407070c6 +size 12072 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png index 1cf8978bcb..30f75826eb 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:038d07eb02ed4fdfabfd97a4c7f4e1f1be25ae7ea874bac0ab192a18ea6be397 -size 12760 +oid sha256:f7838c37c32134f325960312095ed8e1decbb0dd7e14a84e82637258c7ea117e +size 12826 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png index b5926ee62c..af9954116a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc402424e236ec35f0b510451533b1566dd9c4d4dea45af93aab8279f5f5abbe -size 10880 +oid sha256:0166ad5236ecdcc943d839fad092fe3899dcd4e418703846c492edb7700e4726 +size 10682 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png index 3a24b61af1..5b8c5127c0 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:92c44ac71bf6822f12c8e90e1727da8db6e802c293f7945e5e6f6a9c311faccf -size 14115 +oid sha256:aaeee39c61b86d9ce569ca2288f998b8461a3f2169dac23cf2f750dd475d8b81 +size 14145 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png index 476a346c68..93fa5c1de3 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fcc5ba9e73231485a4cfc3d38a6692762b079aa4057c7b32177c982a64b786f2 -size 12632 +oid sha256:5908ff88ddaa6eb3faea6174d87b0182e4407b11812ad70ddcd39c6619b6a5c5 +size 12615 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png index e00a684ee5..af2345fe52 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:36f5aea2b06ca8d8f04beac2abd75a3620913e16f4ae55173b3b5cb371924d3f -size 13256 +oid sha256:b6852daae665638e38c0b7ff58b2a0de1d5df9dd771c5cbccbbb83ff78e6a1d7 +size 12741 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png index 6d8df6c27a..3f91a9259c 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d77d1c95fcc3dbe43c34bc94733eb6e8b3d007d023883f9bf18c9d9373444882 -size 13287 +oid sha256:6d86473ff1024fc53373b1dba49fc14283b8a323d6b85ba3e16f41ebff8288d0 +size 12845 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png index b5926ee62c..af9954116a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:cc402424e236ec35f0b510451533b1566dd9c4d4dea45af93aab8279f5f5abbe -size 10880 +oid sha256:0166ad5236ecdcc943d839fad092fe3899dcd4e418703846c492edb7700e4726 +size 10682 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png index 9ecfcb1fff..878a36a477 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WernerPaletteQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:30f8c8275afb6c61803facee006f3a181151e4d3d09a398eba60704a8e799df9 -size 13834 +oid sha256:b2bd11fa19fab712b5cd6c2b36d673c7dce904b5032b860d257b00e095e4aadf +size 13432 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png index fbe6fedca5..dba9232097 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c -size 15368 +oid sha256:faa91657288e6a6797d8459d41d5fecca3c0a2e8e63317ebaf47df28688d13d7 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png index 566e1befe4..ea062d5be6 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:20f45d86bdedce746fcd807d4abd6eda645c10064233d84ecf12613bcdcfc131 -size 15372 +oid sha256:79e48506430f3a9b25f484ef191fd820819c438392a4e588c2ecafb6db9a2210 +size 13775 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png index 40ede8647c..ae90ea9b5f 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:70638fa2140e8400683ef7b2914cf877cbfe81a44847035239165e81357d9f55 -size 15707 +oid sha256:f56c884a0e4666cd662d36ec3a0d4e751c899c0122595378154507fffc69fda4 +size 14010 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png index fbe6fedca5..dba9232097 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c -size 15368 +oid sha256:faa91657288e6a6797d8459d41d5fecca3c0a2e8e63317ebaf47df28688d13d7 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png index be922bfe5d..1e1795063b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_ErrorDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a33e1510a59a7abd38ba4e97d18428aa76bc6bdad9016f2d279b996a8f0ea0a3 -size 16040 +oid sha256:4095927693b3cd49df58c0c1d7c5430255350c9ae595408a52ad83b1a65614ac +size 14269 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png index 2debe15ab4..29a3ed7ffd 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.25.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:9a209b60feda34e2078fe0609e8e32a67901d1ec0d99fe500e4d7968031f62df -size 17253 +oid sha256:d062d4b79ee01942776ae13467e9bcbb529a7eeb5ad7c28ff3d0ccd3d88dcde6 +size 15962 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png index 447ffb0ee6..50fa46d169 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.5.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5383256fd20787dcce51bf8d13af94172ea47e2bda8ae1285768d422c3d08f61 -size 17531 +oid sha256:47b2265af41ba042904cab387bf1de4715bd4d8a318bc6c1f69bfdbff5eabe2c +size 16928 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png index b991ad6599..5d1030e6b8 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.75.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b754d74a036eff2a56ebea8fce81d952db54f05c6ec247cfe5bb76eacbf0c33f -size 17949 +oid sha256:6679d6d6f7c8b44461956b54654cea71180a2b0d43712d3775e60cbedd90cc82 +size 17520 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png index fbe6fedca5..dba9232097 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_0.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b09ecc73b2366eb5ab50ac07eab5bba0643d4d26a71e4d8af6235da2ac35631c -size 15368 +oid sha256:faa91657288e6a6797d8459d41d5fecca3c0a2e8e63317ebaf47df28688d13d7 +size 13853 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png index cd3527df31..567e5d6a3b 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantizationWithDitheringScale_david_WuQuantizer_OrderedDither_1.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fdf77c8222a40afcfdda5edeb87b7921c71b1368ac7f91cc560e8d73676fdb33 -size 18115 +oid sha256:5af5d16f875172d73f8426928fc8edaa4a6cab321a968b6c29fca32d0fba0df5 +size 18182 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png index 4013073c10..09c471914a 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:374a09cf2f904bc512bafb1d280f5de484bf101bb7d24d4dfef0f5fe22f2ed39 -size 82110 +oid sha256:a40b319d264f046159722cb57599eda51de9ba3795272b3785901cdc51053fab +size 83010 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png index f8c459512b..3bd7cbabbb 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2a4564e26e53e6562ca4dfa44e671150903e022db4f6ec76038627bca130bbe9 -size 54177 +oid sha256:3bc93509a983e20986614f4937f66d5d979bbb433a30a7736150934cf14b452a +size 55213 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png index 834c5ffe6b..34490e602d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:00ede0da073e60deba1f0eb7cc5f3da0902b44dfcea71cbf33a56fc74955823b -size 79449 +oid sha256:b92f3320120d53444cefc79b4684933cfe2b933dc79c2414496785743b5c8f18 +size 80808 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png index 7ceb6114ad..40243937d3 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7ce4b978b800820275635ae8da59212661c74a1b6ba9050ebf052c87315aedef -size 62107 +oid sha256:b63810145832db459bb7a6b37a028a7b778f6b6b4e6eae00e50e6e21c5a06086 +size 62199 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png index 570db6a3a9..5e9fa12332 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:602181e876201b10f75650eb07961fa499c05009067c7d298d4826e1503b93ca -size 33091 +oid sha256:f90db3ce2153cc9ba4d1d79e5749dc4d49e916dff8a0e121ebce9b00702cfcc8 +size 33880 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png index 9710298a3d..68a95a0540 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a2a534bc0862e0d7325e9d6bbdf1c73ddc356bd621dfdc64a9c0c04399a93e00 -size 43807 +oid sha256:8af98bfcc5edef3f3ff33ee8f76f33ce2906a6677167e2b29e1dbe63b00a78d8 +size 44202 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png index 062113ae68..96c66aad72 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8906591aa17712c67939d40ada949e10c8de0cdaac5186a88db1199ac1819bd3 -size 33835 +oid sha256:828b082a1892f0200ef84254637b340b1276e1bee44e01c6b715de8838e4818f +size 35301 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png index 8fd221575a..3ff151f6d0 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:545a01286eff5b5835e79b595fe482f2f5e571972dfdbff651eb5db2944d7889 -size 33045 +oid sha256:f70d1aa2f985dfb7227ea5fd7b4b98effc1a31c89fd05bbee9cfa8f003b9cb4e +size 34261 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png index 877ed87781..10daff76b2 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2f34ecadac596bccfb2fcc5cc7f070ea98917a30d036bee558775c01737c72d2 -size 43016 +oid sha256:d8ba00e2948337f77d935d98349958c6a520958671e9ec714ff1bfadfb130e72 +size 44622 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png index 7869d6f134..747ca70c1d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:d713b040dbe51d9034cd7c3b1055b64a21c9146e6417c7c35f1012f4093b872c -size 104792 +oid sha256:d58c425ce5b1ca56450095a66dea24b379935b0087aec7b4102f15a99f95a017 +size 101999 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png index d6f69a5bde..de464b94cc 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0773406e402e8c30bb345de5e4e20f2546a3ad692b9ad0b29dfe3df8c659cf4b -size 83576 +oid sha256:93a4822e39babba059a88536a965e4f3207e4402d2b92d7d18485fec5e9e69da +size 84378 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png index c8d7908efe..ce54548279 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_Bike_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6b75b9c856570b0b2bfd8826eb8771bf15b74f309ee70aae72a607e96040e254 -size 99413 +oid sha256:35969c8dc96de4dacc3048ae760a0681278a2011993a0edbceaacc93d6fc3a67 +size 102713 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png index b56b714e88..5efcaedc94 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7a609150bfad93dc56bf9e1c3214ea3eabec48dd73939945840656de544bd423 -size 94976 +oid sha256:40d012f4ecb4e36c94d086f8ec7bc199fbfd9fb30a9427a07b35df1b1e430a71 +size 95601 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png index bd2913174b..916dc37566 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:b06aa4d0f3caca205cb5adcdcf26bf6ec6157febdd9266a3fcda9179deaf0840 -size 77036 +oid sha256:fa64863f73dfd1c5daef645c54e9275136f66513a87750bee0ec8e13ac357da5 +size 79649 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png index ab2a2e3f6b..f039dd222e 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_OctreeQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:66c47408a07b7e32d7cabc64289aa8f16b0c96e5ca4c478ebae48729ff55b229 -size 91645 +oid sha256:8f5138589c606de20ba193d4279f049ee1ecb3f1801b949d3436995bbf242cbe +size 92683 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png index 0364487787..2b897a5d6d 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:ded9cb4986e620f5fc11486ccdf81934dff7b3cea7db7e292929d339ecc21714 -size 60116 +oid sha256:007ac609ec61b39c7bdd04bc87a698f5cdc76eadd834c1457f41eb9c135c3f7b +size 60688 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png index a798459cb8..e40a91cbc4 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5da4f2f3024fe3c8ae7f0ce6113f78c74d699eb4efe41f1d9df875af05d09547 -size 46806 +oid sha256:6fc2f82bdbf4b204ad78f3bb54bfdea7452a2d1430814f45262fd309225f2fc0 +size 46727 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png index 687cd1dbca..ac56fa9236 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WebSafePaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:e2d47f277bc904ed8c3b3bbfe636b647884511de39661bfd34cdcb2abe9f6a13 -size 50818 +oid sha256:6d2289ed4fa0c679f0f120d260fec8ab40b1599043cc0a1fbebc6b67e238ff87 +size 51428 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png index 8e0f6002c6..8b79a19e05 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:4324dc77448aeb0ee4ebe39c449ddedff81bf6f0243e0c4713ae89a18b13f0b8 -size 67273 +oid sha256:ef2b6073b75a2de97a78d47d3b3e40c264687c5756f153d3d85bc5b2714cf85a +size 68226 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png index 33c9d43247..8d0d2b60db 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:eb0a2e6d50625ae9a67f9d36d3296f65e41bb6d5a7d3e8163dba89333e3ac6a3 -size 63442 +oid sha256:ac1424c6c4c18feb42106e14da6b161ce3f48276d0aa6603ca60ad5caa0a5338 +size 63764 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png index f3900e5f6c..88cf83a306 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WernerPaletteQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:6551261b6b8c4cf4f69ba2860e163fe10fc9f2660cbb43c1423a9b5dd9456040 -size 68497 +oid sha256:513844ed95c2b50e792d3346398256846b8b280dbadf7ef3f4e11d58c1e679c0 +size 69529 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png index 6203feb92d..a3eefcba20 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_ErrorDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:5f5cf2a5917f8edf77cfc78b8d923bda672435da095876390bd14212bfd87d75 -size 112571 +oid sha256:32b269d62d4eebe555d5d9f12b9958b41206848504bb985dcd1ff9c81a5003c6 +size 117073 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png index 1625e16862..3b0c46ac38 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_NoDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:abd3ad65543bf9bdfb9924652cc107b23c80db3e210d2b994fd575ea73475aa7 -size 108014 +oid sha256:12f58b00a16913cd85ffa18fcea580a59550dcc201295b060d55a870230f37f7 +size 113995 diff --git a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png index 19a672d804..328f863307 100644 --- a/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png +++ b/tests/Images/External/ReferenceOutput/QuantizerTests/ApplyQuantization_CalliphoraPartial_WuQuantizer_OrderedDither.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:a27a605acbd026ba475fae9110c69c6002a399ef3747ce7ca5c060a6df5a078b -size 114379 +oid sha256:867d7b727de278cbc01b7d2b8e968f1fc0d0a81a3e4af636ce4a6598a8709be6 +size 114630 From 5da17f3992b142399615fa49db28d0979257a1a0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 12:03:14 +1000 Subject: [PATCH 065/219] Enable Sse2, simplify --- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 31 +++++++++++++ src/ImageSharp/Formats/AnimationUtilities.cs | 46 +++++++++++++++++++ src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 5 +- src/ImageSharp/Formats/Png/PngMetadata.cs | 17 +++---- .../TestUtilities/TestEnvironment.Formats.cs | 1 - 5 files changed, 86 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 7caaa5868d..fc58ef3440 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; @@ -656,6 +657,36 @@ internal static partial class SimdUtils return AdvSimd.BitwiseSelect(signedMask, right.AsInt16(), left.AsInt16()).AsByte(); } + /// + /// Blend packed 32-bit unsigned integers from and using . + /// The high bit of each corresponding byte determines the selection. + /// If the high bit is set the element of is selected. + /// The element of is selected otherwise. + /// + /// The left vector. + /// The right vector. + /// The mask vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 BlendVariable(Vector128 left, Vector128 right, Vector128 mask) + => BlendVariable(left.AsByte(), right.AsByte(), mask.AsByte()).AsUInt32(); + + /// + /// Count the number of leading zero bits in a mask. + /// Similar in behavior to the x86 instruction LZCNT. + /// + /// The value. + public static ushort LeadingZeroCount(ushort value) + => (ushort)(BitOperations.LeadingZeroCount(value) - 16); + + /// + /// Count the number of trailing zero bits in an integer value. + /// Similar in behavior to the x86 instruction TZCNT. + /// + /// The value. + public static ushort TrailingZeroCount(ushort value) + => (ushort)(BitOperations.TrailingZeroCount(value << 16) - 16); + /// /// as many elements as possible, slicing them down (keeping the remainder). /// diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 23fc40cdfe..3c731422ad 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -128,6 +128,52 @@ internal static class AnimationUtilities } } + if (Sse2.IsSupported && remaining >= 4) + { + Vector128 r128 = previousFrame != null ? Vector128.Create(bg.PackedValue) : Vector128.Zero; + Vector128 vmb128 = Vector128.Zero; + if (blend) + { + vmb128 = Sse2.CompareEqual(vmb128, vmb128); + } + + while (remaining >= 4) + { + Vector128 p = Unsafe.Add(ref Unsafe.As, Vector128>(ref previousBase), x); + Vector128 c = Unsafe.Add(ref Unsafe.As, Vector128>(ref currentBase), x); + + Vector128 eq = Sse2.CompareEqual(p, c); + Vector128 r = SimdUtils.HwIntrinsics.BlendVariable(c, r128, Sse2.And(eq, vmb128)); + + if (nextFrame != null) + { + Vector128 n = Sse2.ShiftRightLogical(Unsafe.Add(ref Unsafe.As, Vector128>(ref nextBase), x), 24).AsInt32(); + eq = Sse2.AndNot(Sse2.CompareGreaterThan(Sse2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq); + } + + Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase), x) = r.AsByte(); + + ushort msk = (ushort)(uint)Sse2.MoveMask(eq.AsByte()); + msk = (ushort)~msk; + if (msk != 0) + { + // If is diff is found, the left side is marked by the min of previously found left side and the start position. + // The right is the max of the previously found right side and the end position. + int start = i + (SimdUtils.HwIntrinsics.TrailingZeroCount(msk) / sizeof(uint)); + int end = i + (4 - (SimdUtils.HwIntrinsics.LeadingZeroCount(msk) / sizeof(uint))); + left = Math.Min(left, start); + right = Math.Max(right, end); + hasRowDiff = true; + hasDiff = true; + } + + x++; + i += 4; + remaining -= 4; + } + } + + // TODO: AdvSimd ?? for (i = remaining; i > 0; i--) { x = (uint)(length - i); diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 2186cc2e45..f0e1aafd7d 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -168,7 +168,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals stream.WriteByte(GifConstants.EndIntroducer); - quantized.Dispose(); + quantized?.Dispose(); } private static GifMetadata GetGifMetadata(Image image) @@ -251,6 +251,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { // Gather the metadata for this frame. ImageFrame currentFrame = image.Frames[i]; + ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; GifFrameMetadata gifMetadata = GetGifFrameMetadata(currentFrame, globalTransparencyIndex); bool useLocal = this.colorTableMode == GifColorTableMode.Local || (gifMetadata.ColorTableMode == GifColorTableMode.Local); @@ -264,8 +265,6 @@ internal sealed class GifEncoderCore : IImageEncoderInternals hasPaletteQuantizer = true; } - ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; - this.EncodeAdditionalFrame( stream, previousFrame, diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 128237684c..93ddcf2636 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -90,13 +90,12 @@ public class PngMetadata : IDeepCloneable { // Should the conversion be from a format that uses a 24bit palette entries (gif) // we need to clone and adjust the color table to allow for transparency. - ReadOnlyMemory? colorTable = metadata.ColorTable; - if (metadata.ColorTable.HasValue) + Color[]? colorTable = metadata.ColorTable.HasValue ? metadata.ColorTable.Value.ToArray() : null; + if (colorTable != null) { - Color[] clone = metadata.ColorTable.Value.ToArray(); - for (int i = 0; i < clone.Length; i++) + for (int i = 0; i < colorTable.Length; i++) { - ref Color c = ref clone[i]; + ref Color c = ref colorTable[i]; if (c == metadata.BackgroundColor) { // Png treats background as fully empty @@ -104,15 +103,13 @@ public class PngMetadata : IDeepCloneable break; } } - - colorTable = clone; } return new() { - ColorType = colorTable.HasValue ? PngColorType.Palette : null, - BitDepth = colorTable.HasValue - ? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Value.Length), 1, 8) + ColorType = colorTable != null ? PngColorType.Palette : null, + BitDepth = colorTable != null + ? (PngBitDepth)Numerics.Clamp(ColorNumerics.GetBitsNeededForColorDepth(colorTable.Length), 1, 8) : null, ColorTable = colorTable, RepeatCount = metadata.RepeatCount, diff --git a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs index 6c6f300d02..9508de2469 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestEnvironment.Formats.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Diagnostics.CodeAnalysis; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Bmp; using SixLabors.ImageSharp.Formats.Gif; From 10cd3d514af39825d0b517ec11e7ba4023af9a96 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 12:19:13 +1000 Subject: [PATCH 066/219] Update AnimationUtilities.cs --- src/ImageSharp/Formats/AnimationUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 3c731422ad..727364227e 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -43,7 +43,7 @@ internal static class AnimationUtilities where TPixel : unmanaged, IPixel { MemoryAllocator memoryAllocator = configuration.MemoryAllocator; - IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 4, AllocationOptions.Clean); + using IMemoryOwner buffers = memoryAllocator.Allocate(currentFrame.Width * 4, AllocationOptions.Clean); Span previous = buffers.GetSpan()[..currentFrame.Width]; Span current = buffers.GetSpan().Slice(currentFrame.Width, currentFrame.Width); Span next = buffers.GetSpan().Slice(currentFrame.Width * 2, currentFrame.Width); From f4dc0fc4f2d9db47c4100e1985dbdb98eee3b04e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 12:56:43 +1000 Subject: [PATCH 067/219] Disable Sse2 for now. --- src/ImageSharp/Formats/AnimationUtilities.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 727364227e..5e576c983f 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -128,7 +128,8 @@ internal static class AnimationUtilities } } - if (Sse2.IsSupported && remaining >= 4) + // TODO: There's a bug here. See WebpEncoderTests.Encode_AnimatedLossless + if (Sse2.IsSupported && remaining >= 4 && false) { Vector128 r128 = previousFrame != null ? Vector128.Create(bg.PackedValue) : Vector128.Zero; Vector128 vmb128 = Vector128.Zero; @@ -151,7 +152,7 @@ internal static class AnimationUtilities eq = Sse2.AndNot(Sse2.CompareGreaterThan(Sse2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq); } - Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase), x) = r.AsByte(); + Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase), x) = r; ushort msk = (ushort)(uint)Sse2.MoveMask(eq.AsByte()); msk = (ushort)~msk; From 43c86145305e48fb6d3e28300dc0a8be5e8a4cb1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 13:31:38 +1000 Subject: [PATCH 068/219] Fix Sse2 offset --- src/ImageSharp/Formats/AnimationUtilities.cs | 29 ++++++++++---------- 1 file changed, 15 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 5e576c983f..814e48b63f 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -71,10 +71,10 @@ internal static class AnimationUtilities PixelOperations.Instance.ToRgba32(configuration, nextFrame.DangerousGetPixelRowMemory(y).Span, next); } - ref Vector256 previousBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(previous)); - ref Vector256 currentBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(current)); - ref Vector256 nextBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(next)); - ref Vector256 resultBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); + ref Vector256 previousBase256 = ref Unsafe.As>(ref MemoryMarshal.GetReference(previous)); + ref Vector256 currentBase256 = ref Unsafe.As>(ref MemoryMarshal.GetReference(current)); + ref Vector256 nextBase256 = ref Unsafe.As>(ref MemoryMarshal.GetReference(next)); + ref Vector256 resultBase256 = ref Unsafe.As>(ref MemoryMarshal.GetReference(result)); int i = 0; uint x = 0; @@ -93,19 +93,19 @@ internal static class AnimationUtilities while (remaining >= 8) { - Vector256 p = Unsafe.Add(ref previousBase, x).AsUInt32(); - Vector256 c = Unsafe.Add(ref currentBase, x).AsUInt32(); + Vector256 p = Unsafe.Add(ref previousBase256, x).AsUInt32(); + Vector256 c = Unsafe.Add(ref currentBase256, x).AsUInt32(); Vector256 eq = Avx2.CompareEqual(p, c); Vector256 r = Avx2.BlendVariable(c, r256, Avx2.And(eq, vmb256)); if (nextFrame != null) { - Vector256 n = Avx2.ShiftRightLogical(Unsafe.Add(ref nextBase, x).AsUInt32(), 24).AsInt32(); + Vector256 n = Avx2.ShiftRightLogical(Unsafe.Add(ref nextBase256, x).AsUInt32(), 24).AsInt32(); eq = Avx2.AndNot(Avx2.CompareGreaterThan(Avx2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq); } - Unsafe.Add(ref resultBase, x) = r.AsByte(); + Unsafe.Add(ref resultBase256, x) = r.AsByte(); uint msk = (uint)Avx2.MoveMask(eq.AsByte()); msk = ~msk; @@ -128,9 +128,10 @@ internal static class AnimationUtilities } } - // TODO: There's a bug here. See WebpEncoderTests.Encode_AnimatedLossless - if (Sse2.IsSupported && remaining >= 4 && false) + if (Sse2.IsSupported && remaining >= 4) { + // Update offset since we may be operating on the remainder previously incremented by pixel steps of 8. + x *= 2; Vector128 r128 = previousFrame != null ? Vector128.Create(bg.PackedValue) : Vector128.Zero; Vector128 vmb128 = Vector128.Zero; if (blend) @@ -140,19 +141,19 @@ internal static class AnimationUtilities while (remaining >= 4) { - Vector128 p = Unsafe.Add(ref Unsafe.As, Vector128>(ref previousBase), x); - Vector128 c = Unsafe.Add(ref Unsafe.As, Vector128>(ref currentBase), x); + Vector128 p = Unsafe.Add(ref Unsafe.As, Vector128>(ref previousBase256), x); + Vector128 c = Unsafe.Add(ref Unsafe.As, Vector128>(ref currentBase256), x); Vector128 eq = Sse2.CompareEqual(p, c); Vector128 r = SimdUtils.HwIntrinsics.BlendVariable(c, r128, Sse2.And(eq, vmb128)); if (nextFrame != null) { - Vector128 n = Sse2.ShiftRightLogical(Unsafe.Add(ref Unsafe.As, Vector128>(ref nextBase), x), 24).AsInt32(); + Vector128 n = Sse2.ShiftRightLogical(Unsafe.Add(ref Unsafe.As, Vector128>(ref nextBase256), x), 24).AsInt32(); eq = Sse2.AndNot(Sse2.CompareGreaterThan(Sse2.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32(), eq); } - Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase), x) = r; + Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase256), x) = r; ushort msk = (ushort)(uint)Sse2.MoveMask(eq.AsByte()); msk = (ushort)~msk; From cf4106b78c1b85ae7e5384abd28506c34b15ffd6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 16:50:39 +1000 Subject: [PATCH 069/219] Add note --- src/ImageSharp/Formats/AnimationUtilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 814e48b63f..67ee72e95a 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -175,7 +175,7 @@ internal static class AnimationUtilities } } - // TODO: AdvSimd ?? + // TODO: v4 AdvSimd when we can use .NET 8 for (i = remaining; i > 0; i--) { x = (uint)(length - i); From 48cecd3c184fb686f7138257cc08517ec6b49aa4 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 17:21:22 +1000 Subject: [PATCH 070/219] Make JFIF marker optional --- .../Formats/Jpeg/Components/Decoder/JFifMarker.cs | 3 +-- .../Formats/Jpeg/Components/Decoder/ProfileResolver.cs | 8 -------- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 5 +---- tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 2 +- 4 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs index 060572fc3f..7e25e945a5 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JFifMarker.cs @@ -73,8 +73,7 @@ internal readonly struct JFifMarker : IEquatable { // Some images incorrectly use JFXX as the App0 marker (Issue 2478) if (ProfileResolver.IsProfile(bytes, ProfileResolver.JFifMarker) - || ProfileResolver.IsProfile(bytes, ProfileResolver.JFxxMarker) - || ProfileResolver.IsProfile(bytes, ProfileResolver.OSQidMaker)) + || ProfileResolver.IsProfile(bytes, ProfileResolver.JFxxMarker)) { byte majorVersion = bytes[5]; byte minorVersion = bytes[6]; diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs index ed916c205b..c11679feb1 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ProfileResolver.cs @@ -24,14 +24,6 @@ internal static class ProfileResolver (byte)'J', (byte)'F', (byte)'X', (byte)'X', (byte)'\0' }; - /// - /// Gets the \n[ID or 10 91 73 68 32 specific markers. - /// - public static ReadOnlySpan OSQidMaker => new[] - { - (byte)'\n', (byte)'[', (byte)'I', (byte)'D', (byte)' ' - }; - /// /// Gets the ICC specific markers. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 83a828caaf..ccace190f9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -753,10 +753,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals Span temp = stackalloc byte[2 * 16 * 4]; stream.Read(temp, 0, JFifMarker.Length); - if (!JFifMarker.TryParse(temp, out this.jFif)) - { - JpegThrowHelper.ThrowNotSupportedException("Unknown App0 Marker - Expected JFIF."); - } + _ = JFifMarker.TryParse(temp, out this.jFif); remaining -= JFifMarker.Length; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index f872895227..deea9217f0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -330,7 +330,7 @@ public partial class JpegDecoderTests [Theory] [WithFile(TestImages.Jpeg.Issues.Issue2564, PixelTypes.Rgba32)] public void Issue2564_DecodeWorks(TestImageProvider provider) - where TPixel : unmanaged, IPixel + where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(JpegDecoder.Instance); image.DebugSave(provider); From c99c83ae61a7aa1fdeabfa6fb18b49fe4af77a97 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 19:44:10 +1000 Subject: [PATCH 071/219] Create fine-grained options for CRC handling. --- src/ImageSharp/Formats/Png/PngChunk.cs | 14 +++++---- .../Formats/Png/PngCrcChunkHandling.cs | 30 +++++++++++++++++++ src/ImageSharp/Formats/Png/PngDecoderCore.cs | 18 +++++------ .../Formats/Png/PngDecoderOptions.cs | 5 ++-- .../Formats/Png/PngDecoderTests.cs | 2 +- 5 files changed, 49 insertions(+), 20 deletions(-) create mode 100644 src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs diff --git a/src/ImageSharp/Formats/Png/PngChunk.cs b/src/ImageSharp/Formats/Png/PngChunk.cs index e5fa5fbb72..6ec0df9ad6 100644 --- a/src/ImageSharp/Formats/Png/PngChunk.cs +++ b/src/ImageSharp/Formats/Png/PngChunk.cs @@ -41,9 +41,13 @@ internal readonly struct PngChunk /// /// Gets a value indicating whether the given chunk is critical to decoding /// - public bool IsCritical => - this.Type is PngChunkType.Header or - PngChunkType.Palette or - PngChunkType.Data or - PngChunkType.FrameData; + /// The chunk CRC handling behavior. + public bool IsCritical(PngCrcChunkHandling handling) + => handling switch + { + PngCrcChunkHandling.IgnoreNone => true, + PngCrcChunkHandling.IgnoreNonCritical => this.Type is PngChunkType.Header or PngChunkType.Palette or PngChunkType.Data or PngChunkType.FrameData, + PngCrcChunkHandling.IgnoreData => this.Type is PngChunkType.Header or PngChunkType.Palette, + _ => false, + }; } diff --git a/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs b/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs new file mode 100644 index 0000000000..264d737fdc --- /dev/null +++ b/src/ImageSharp/Formats/Png/PngCrcChunkHandling.cs @@ -0,0 +1,30 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Png; + +/// +/// Specifies how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG. +/// +public enum PngCrcChunkHandling +{ + /// + /// Do not ignore any CRC chunk errors. + /// + IgnoreNone, + + /// + /// Ignore CRC errors in non critical chunks. + /// + IgnoreNonCritical, + + /// + /// Ignore CRC errors in data chunks. + /// + IgnoreData, + + /// + /// Ignore CRC errors in all chunks. + /// + IgnoreAll +} diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 355a0bfcf7..4edbe50c78 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -115,9 +115,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private PngChunk? nextChunk; /// - /// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored. + /// How to handle CRC errors. /// - private bool ignoreCrcErrors; + private readonly PngCrcChunkHandling pngCrcChunkHandling; /// /// Initializes a new instance of the class. @@ -130,7 +130,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.maxFrames = options.GeneralOptions.MaxFrames; this.skipMetadata = options.GeneralOptions.SkipMetadata; this.memoryAllocator = this.configuration.MemoryAllocator; - this.ignoreCrcErrors = options.IgnoreCrcCheck; + this.pngCrcChunkHandling = options.PngCrcChunkHandling; } internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly) @@ -141,7 +141,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.skipMetadata = true; this.configuration = options.GeneralOptions.Configuration; this.memoryAllocator = this.configuration.MemoryAllocator; - this.ignoreCrcErrors = options.IgnoreCrcCheck; + this.pngCrcChunkHandling = options.PngCrcChunkHandling; } /// @@ -1797,11 +1797,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals type: type, data: this.ReadChunkData(length)); - if (!this.ignoreCrcErrors) - { - this.ValidateChunk(chunk, buffer); - } - + this.ValidateChunk(chunk, buffer); + // Restore the stream position for IDAT and fdAT chunks, because it will be decoded later and // was only read to verifying the CRC is correct. if (type is PngChunkType.Data or PngChunkType.FrameData) @@ -1820,8 +1817,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private void ValidateChunk(in PngChunk chunk, Span buffer) { uint inputCrc = this.ReadChunkCrc(buffer); - - if (chunk.IsCritical) + if (chunk.IsCritical(this.pngCrcChunkHandling)) { Span chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs index c952a18ef2..ab6ba4770e 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs @@ -12,8 +12,7 @@ public sealed class PngDecoderOptions : ISpecializedDecoderOptions public DecoderOptions GeneralOptions { get; init; } = new DecoderOptions(); /// - /// If true, ADLER32 checksum in the IDAT chunk as well as the chunk CRCs will be ignored. - /// Similar to PNG_CRC_QUIET_USE in libpng. + /// Gets a value indicating how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG. /// - public bool IgnoreCrcCheck { get; init; } + public PngCrcChunkHandling PngCrcChunkHandling { get; init; } = PngCrcChunkHandling.IgnoreNonCritical; } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 5351af4fcc..cbb625bdf4 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -475,7 +475,7 @@ public partial class PngDecoderTests public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors(TestImageProvider provider) where TPixel : unmanaged, IPixel { - using Image image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { IgnoreCrcCheck = true }); + using Image image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }); image.DebugSave(provider); image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); From 3d9ceaa8fad18a755ae682bec2dbe74cfc6c59d7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 21:31:48 +1000 Subject: [PATCH 072/219] Allow decoding early EOF --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 50 +++++++++++++++---- .../Formats/Png/PngDecoderTests.cs | 19 +++++-- tests/ImageSharp.Tests/TestImages.cs | 1 + .../TestUtilities/EofHitCounter.cs | 15 ++++++ tests/Images/Input/Png/issues/Issue_2589.png | 3 ++ 5 files changed, 72 insertions(+), 16 deletions(-) create mode 100644 tests/Images/Input/Png/issues/Issue_2589.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 4edbe50c78..64f1e00fff 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -583,11 +583,23 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private void InitializeImage(ImageMetadata metadata, FrameControl frameControl, out Image image) where TPixel : unmanaged, IPixel { - image = Image.CreateUninitialized( - this.configuration, - this.header.Width, - this.header.Height, - metadata); + // When ignoring data CRCs, we can't use the image constructor that leaves the buffer uncleared. + if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) + { + image = new Image( + this.configuration, + this.header.Width, + this.header.Height, + metadata); + } + else + { + image = Image.CreateUninitialized( + this.configuration, + this.header.Width, + this.header.Height, + metadata); + } PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngFrameMetadata(); frameMetadata.FromChunk(in frameControl); @@ -808,6 +820,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; default: + if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) + { + goto EXIT; + } + PngThrowHelper.ThrowUnknownFilter(); break; } @@ -817,6 +834,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals currentRow++; } + EXIT: blendMemory?.Dispose(); } @@ -908,6 +926,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; default: + if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) + { + goto EXIT; + } + PngThrowHelper.ThrowUnknownFilter(); break; } @@ -942,6 +965,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals } } + EXIT: blendMemory?.Dispose(); } @@ -1761,21 +1785,25 @@ internal sealed class PngDecoderCore : IImageDecoderInternals return true; } - if (!this.TryReadChunkLength(buffer, out int length)) + if (this.currentStream.Position == this.currentStream.Length) { chunk = default; + return false; + } + if (!this.TryReadChunkLength(buffer, out int length)) + { // IEND + chunk = default; return false; } - while (length < 0 || length > (this.currentStream.Length - this.currentStream.Position)) + while (length < 0) { // Not a valid chunk so try again until we reach a known chunk. if (!this.TryReadChunkLength(buffer, out length)) { chunk = default; - return false; } } @@ -1791,9 +1819,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals return true; } - long pos = this.currentStream.Position; + long position = this.currentStream.Position; chunk = new PngChunk( - length: length, + length: (int)Math.Min(length, this.currentStream.Length - position), type: type, data: this.ReadChunkData(length)); @@ -1803,7 +1831,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals // was only read to verifying the CRC is correct. if (type is PngChunkType.Data or PngChunkType.FrameData) { - this.currentStream.Position = pos; + this.currentStream.Position = position; } return true; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index cbb625bdf4..ee6e15d7dc 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -470,15 +470,21 @@ public partial class PngDecoderTests Assert.Contains("CRC Error. PNG IDAT chunk is corrupt!", ex.Message); } + // https://github.com/SixLabors/ImageSharp/pull/2589 [Theory] - [WithFile(TestImages.Png.Bad.WrongCrcDataChunk, PixelTypes.Rgba32)] - public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors(TestImageProvider provider) + [WithFile(TestImages.Png.Bad.WrongCrcDataChunk, PixelTypes.Rgba32, true)] + [WithFile(TestImages.Png.Bad.Issue2589, PixelTypes.Rgba32, false)] + public void Decode_InvalidDataChunkCrc_IgnoreCrcErrors(TestImageProvider provider, bool compare) where TPixel : unmanaged, IPixel { using Image image = provider.GetImage(PngDecoder.Instance, new PngDecoderOptions() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }); image.DebugSave(provider); - image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); + if (compare) + { + // Magick cannot actually decode this image to compare. + image.CompareToOriginal(provider, new MagickReferenceDecoder(false)); + } } // https://github.com/SixLabors/ImageSharp/issues/1014 @@ -651,9 +657,12 @@ public partial class PngDecoderTests [Fact] public void Binary_PrematureEof() { - using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446); + PngDecoder decoder = PngDecoder.Instance; + PngDecoderOptions options = new() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }; + using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446, decoder, options); - Assert.True(eofHitCounter.EofHitCount <= 2); + // TODO: Undo this. + Assert.True(eofHitCounter.EofHitCount <= 6); Assert.Equal(new Size(200, 120), eofHitCounter.Image.Size); } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 0d9fc55007..ad764628e7 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -157,6 +157,7 @@ public static class TestImages public const string MissingPaletteChunk1 = "Png/missing_plte.png"; public const string MissingPaletteChunk2 = "Png/missing_plte_2.png"; public const string InvalidGammaChunk = "Png/length_gama.png"; + public const string Issue2589 = "Png/issues/Issue_2589.png"; // Zlib errors. public const string ZlibOverflow = "Png/zlib-overflow.png"; diff --git a/tests/ImageSharp.Tests/TestUtilities/EofHitCounter.cs b/tests/ImageSharp.Tests/TestUtilities/EofHitCounter.cs index d949ce0f2d..c5ffdd6489 100644 --- a/tests/ImageSharp.Tests/TestUtilities/EofHitCounter.cs +++ b/tests/ImageSharp.Tests/TestUtilities/EofHitCounter.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.IO; namespace SixLabors.ImageSharp.Tests.TestUtilities; @@ -21,6 +22,11 @@ internal class EofHitCounter : IDisposable public static EofHitCounter RunDecoder(string testImage) => RunDecoder(TestFile.Create(testImage).Bytes); + public static EofHitCounter RunDecoder(string testImage, T decoder, TO options) + where T : SpecializedImageDecoder + where TO : ISpecializedDecoderOptions + => RunDecoder(TestFile.Create(testImage).Bytes, decoder, options); + public static EofHitCounter RunDecoder(byte[] imageData) { BufferedReadStream stream = new(Configuration.Default, new MemoryStream(imageData)); @@ -28,6 +34,15 @@ internal class EofHitCounter : IDisposable return new EofHitCounter(stream, image); } + public static EofHitCounter RunDecoder(byte[] imageData, T decoder, TO options) + where T : SpecializedImageDecoder + where TO : ISpecializedDecoderOptions + { + BufferedReadStream stream = new(options.GeneralOptions.Configuration, new MemoryStream(imageData)); + Image image = decoder.Decode(options, stream); + return new EofHitCounter(stream, image); + } + public void Dispose() { this.stream.Dispose(); diff --git a/tests/Images/Input/Png/issues/Issue_2589.png b/tests/Images/Input/Png/issues/Issue_2589.png new file mode 100644 index 0000000000..f2f159ea70 --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2589.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f7e87701298da4ba0a5cc14e9c04d810125f4958aa338255b14fd19dec15b677 +size 62662 From 091cb1eabc1275dc81789b7b2b7024de8758aa5f Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 21:49:19 +1000 Subject: [PATCH 073/219] More early returns and renaming --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 33 ++++++++++++------- .../Formats/Png/PngDecoderTests.cs | 4 +-- 2 files changed, 24 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 7fb96241a3..84eea9a5a5 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1395,7 +1395,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ReadOnlySpan compressedData = data[(zeroIndex + 2)..]; - if (this.TryUncompressTextData(compressedData, PngConstants.Encoding, out string? uncompressed) + if (this.TryDecompressTextData(compressedData, PngConstants.Encoding, out string? uncompressed) && !TryReadTextChunkMetadata(baseMetadata, name, uncompressed)) { metadata.TextData.Add(new PngTextData(name, uncompressed, string.Empty, string.Empty)); @@ -1539,19 +1539,19 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ReadOnlySpan compressedData = data[(zeroIndex + 2)..]; - if (this.TryUncompressZlibData(compressedData, out byte[] iccpProfileBytes)) + if (this.TryDecompressZlibData(compressedData, out byte[] iccpProfileBytes)) { metadata.IccProfile = new IccProfile(iccpProfileBytes); } } /// - /// Tries to un-compress zlib compressed data. + /// Tries to decompress zlib compressed data. /// /// The compressed data. /// The uncompressed bytes array. /// True, if de-compressing was successful. - private unsafe bool TryUncompressZlibData(ReadOnlySpan compressedData, out byte[] uncompressedBytesArray) + private unsafe bool TryDecompressZlibData(ReadOnlySpan compressedData, out byte[] uncompressedBytesArray) { fixed (byte* compressedDataBase = compressedData) { @@ -1688,7 +1688,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { ReadOnlySpan compressedData = data[dataStartIdx..]; - if (this.TryUncompressTextData(compressedData, PngConstants.TranslatedEncoding, out string? uncompressed)) + if (this.TryDecompressTextData(compressedData, PngConstants.TranslatedEncoding, out string? uncompressed)) { pngMetadata.TextData.Add(new PngTextData(keyword, uncompressed, language, translatedKeyword)); } @@ -1711,9 +1711,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The string encoding to use. /// The uncompressed value. /// The . - private bool TryUncompressTextData(ReadOnlySpan compressedData, Encoding encoding, [NotNullWhen(true)] out string? value) + private bool TryDecompressTextData(ReadOnlySpan compressedData, Encoding encoding, [NotNullWhen(true)] out string? value) { - if (this.TryUncompressZlibData(compressedData, out byte[] uncompressedData)) + if (this.TryDecompressZlibData(compressedData, out byte[] uncompressedData)) { value = encoding.GetString(uncompressedData); return true; @@ -1736,7 +1736,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals Span buffer = stackalloc byte[20]; - _ = this.currentStream.Read(buffer, 0, 4); + int length = this.currentStream.Read(buffer, 0, 4); + if (length == 0) + { + return 0; + } if (this.TryReadChunk(buffer, out PngChunk chunk)) { @@ -1765,7 +1769,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals Span buffer = stackalloc byte[20]; - _ = this.currentStream.Read(buffer, 0, 4); + int length = this.currentStream.Read(buffer, 0, 4); + if (length == 0) + { + return 0; + } if (this.TryReadChunk(buffer, out PngChunk chunk)) { @@ -1802,8 +1810,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals return true; } - if (this.currentStream.Position == this.currentStream.Length) + if (this.currentStream.Position >= this.currentStream.Length - 1) { + // IEND chunk = default; return false; } @@ -1820,6 +1829,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals // Not a valid chunk so try again until we reach a known chunk. if (!this.TryReadChunkLength(buffer, out length)) { + // IEND chunk = default; return false; } @@ -1832,10 +1842,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency && type != PngChunkType.Palette) { chunk = new PngChunk(length, type); - return true; } + // A chunk might report a length that exceeds the length of the stream. + // Take the minimum of the two values to ensure we don't read past the end of the stream. long position = this.currentStream.Position; chunk = new PngChunk( length: (int)Math.Min(length, this.currentStream.Length - position), diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index ee6e15d7dc..bc277bf485 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -661,8 +661,8 @@ public partial class PngDecoderTests PngDecoderOptions options = new() { PngCrcChunkHandling = PngCrcChunkHandling.IgnoreData }; using EofHitCounter eofHitCounter = EofHitCounter.RunDecoder(TestImages.Png.Bad.FlagOfGermany0000016446, decoder, options); - // TODO: Undo this. - Assert.True(eofHitCounter.EofHitCount <= 6); + // TODO: Try to reduce this to 1. + Assert.True(eofHitCounter.EofHitCount <= 3); Assert.Equal(new Size(200, 120), eofHitCounter.Image.Size); } } From 2200ac2b3c1899a5f2573feeda845b736bb8ccc5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 29 Nov 2023 22:53:36 +1000 Subject: [PATCH 074/219] Add test --- .../ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs | 11 +++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/issues/issue2517-bad-d7.jpg | 3 +++ 3 files changed, 15 insertions(+) create mode 100644 tests/Images/Input/Jpg/issues/issue2517-bad-d7.jpg diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index deea9217f0..c8d93f6e9e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -353,4 +353,15 @@ public partial class JpegDecoderTests Assert.Equal(65503, image.Width); Assert.Equal(65503, image.Height); } + + // https://github.com/SixLabors/ImageSharp/issues/2517 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2517, PixelTypes.Rgba32)] + public void Issue2517_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index b6ea20f15c..7a7da22119 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -307,6 +307,7 @@ public static class TestImages public const string Issue2478_JFXX = "Jpg/issues/issue-2478-jfxx.jpg"; public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; + public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/issue2517-bad-d7.jpg b/tests/Images/Input/Jpg/issues/issue2517-bad-d7.jpg new file mode 100644 index 0000000000..002fd8c36c --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue2517-bad-d7.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:650a933db9c4f76fa3e6a8ed35d061a5740c613acd1026d99461eb014d8947b2 +size 179015 From 43cf0bcca495ad169b516b4359edbe6211bf8450 Mon Sep 17 00:00:00 2001 From: Tammo Hinrichs Date: Wed, 29 Nov 2023 14:19:54 +0100 Subject: [PATCH 075/219] fixed png file casing --- tests/Images/Input/Png/{adamheadsHLG.png => adamHeadsHLG.png} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Images/Input/Png/{adamheadsHLG.png => adamHeadsHLG.png} (100%) diff --git a/tests/Images/Input/Png/adamheadsHLG.png b/tests/Images/Input/Png/adamHeadsHLG.png similarity index 100% rename from tests/Images/Input/Png/adamheadsHLG.png rename to tests/Images/Input/Png/adamHeadsHLG.png From c3dacdeee4aaa75a11eba9ff8239bdff144e30cb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 30 Nov 2023 12:23:51 +1000 Subject: [PATCH 076/219] Add AdvSimd implementation --- src/ImageSharp/Formats/AnimationUtilities.cs | 48 +++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 67ee72e95a..288f3d1329 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -6,6 +6,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; @@ -175,7 +176,52 @@ internal static class AnimationUtilities } } - // TODO: v4 AdvSimd when we can use .NET 8 + if (AdvSimd.IsSupported && remaining >= 4) + { + // Update offset since we may be operating on the remainder previously incremented by pixel steps of 8. + x *= 2; + Vector128 r128 = previousFrame != null ? Vector128.Create(bg.PackedValue) : Vector128.Zero; + Vector128 vmb128 = Vector128.Zero; + if (blend) + { + vmb128 = AdvSimd.CompareEqual(vmb128, vmb128); + } + + while (remaining >= 4) + { + Vector128 p = Unsafe.Add(ref Unsafe.As, Vector128>(ref previousBase256), x); + Vector128 c = Unsafe.Add(ref Unsafe.As, Vector128>(ref currentBase256), x); + + Vector128 eq = AdvSimd.CompareEqual(p, c); + Vector128 r = SimdUtils.HwIntrinsics.BlendVariable(c, r128, AdvSimd.And(eq, vmb128)); + + if (nextFrame != null) + { + Vector128 n = AdvSimd.ShiftRightLogical(Unsafe.Add(ref Unsafe.As, Vector128>(ref nextBase256), x), 24).AsInt32(); + eq = AdvSimd.BitwiseClear(eq, AdvSimd.CompareGreaterThan(AdvSimd.ShiftRightLogical(c, 24).AsInt32(), n).AsUInt32()); + } + + Unsafe.Add(ref Unsafe.As, Vector128>(ref resultBase256), x) = r; + + ulong msk = ~AdvSimd.ExtractNarrowingLower(eq).AsUInt64().ToScalar(); + if (msk != 0) + { + // If is diff is found, the left side is marked by the min of previously found left side and the start position. + // The right is the max of the previously found right side and the end position. + int start = i + (BitOperations.TrailingZeroCount(msk) / 16); + int end = i + (4 - (BitOperations.LeadingZeroCount(msk) / 16)); + left = Math.Min(left, start); + right = Math.Max(right, end); + hasRowDiff = true; + hasDiff = true; + } + + x++; + i += 4; + remaining -= 4; + } + } + for (i = remaining; i > 0; i--) { x = (uint)(length - i); From f74b6acacf5a483931c92d259aef27980a17bb03 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 30 Nov 2023 15:03:11 +1000 Subject: [PATCH 077/219] Read resolution from EXIF metadata in WebP --- .../Formats/Webp/WebpDecoderCore.cs | 26 ++++++++++++++++- .../Formats/WebP/WebpDecoderTests.cs | 29 +++++++++++++++++++ 2 files changed, 54 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index de188b137b..69a0afcd9b 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; @@ -339,10 +340,33 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable return; } - metadata.ExifProfile = new ExifProfile(exifData); + ExifProfile exifProfile = new(exifData); + + // Set the resolution from the metadata. + double horizontalValue = GetExifResolutionValue(exifProfile, ExifTag.XResolution); + double verticalValue = GetExifResolutionValue(exifProfile, ExifTag.YResolution); + + if (horizontalValue > 0 && verticalValue > 0) + { + metadata.HorizontalResolution = horizontalValue; + metadata.VerticalResolution = verticalValue; + metadata.ResolutionUnits = UnitConverter.ExifProfileToResolutionUnit(exifProfile); + } + + metadata.ExifProfile = exifProfile; } } + private static double GetExifResolutionValue(ExifProfile exifProfile, ExifTag tag) + { + if (exifProfile.TryGetValue(tag, out IExifValue? resolution)) + { + return resolution.Value.ToDouble(); + } + + return 0; + } + /// /// Reads the XMP profile the stream. /// diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 6301f341cc..c38b13075a 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -4,6 +4,7 @@ using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Formats.Webp; +using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -493,4 +494,32 @@ public class WebpDecoderTests [Fact] public void DecodeLossyWithComplexFilterTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunDecodeLossyWithComplexFilterTest, HwIntrinsics.DisableHWIntrinsic); + + [Theory] + [InlineData(Lossy.BikeWithExif)] + public void Decode_VerifyRatio(string imagePath) + { + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + using Image image = WebpDecoder.Instance.Decode(DecoderOptions.Default, stream); + ImageMetadata meta = image.Metadata; + + Assert.Equal(37.8, meta.HorizontalResolution); + Assert.Equal(37.8, meta.VerticalResolution); + Assert.Equal(PixelResolutionUnit.PixelsPerCentimeter, meta.ResolutionUnits); + } + + [Theory] + [InlineData(Lossy.BikeWithExif)] + public void Identify_VerifyRatio(string imagePath) + { + TestFile testFile = TestFile.Create(imagePath); + using MemoryStream stream = new(testFile.Bytes, false); + ImageInfo image = WebpDecoder.Instance.Identify(DecoderOptions.Default, stream); + ImageMetadata meta = image.Metadata; + + Assert.Equal(37.8, meta.HorizontalResolution); + Assert.Equal(37.8, meta.VerticalResolution); + Assert.Equal(PixelResolutionUnit.PixelsPerCentimeter, meta.ResolutionUnits); + } } From 291e9e7c1e619722ab57b092370483b7adc21c7a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 1 Dec 2023 13:25:20 +1000 Subject: [PATCH 078/219] Use source length as bounds --- .../PixelOperations/Rgb24.PixelOperations.cs | 5 ++- .../PixelFormats/PixelOperations{TPixel}.cs | 16 +++++++-- .../Formats/Jpg/JpegEncoderTests.cs | 36 +++++++++++++++---- 3 files changed, 47 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index 2a8f80ebe0..5473a602f9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -40,6 +40,9 @@ public partial struct Rgb24 Span greenChannel, Span blueChannel, ReadOnlySpan source) - => SimdUtils.UnpackToRgbPlanes(redChannel, greenChannel, blueChannel, source); + { + GuardUnpackIntoRgbPlanes(redChannel, greenChannel, blueChannel, source); + SimdUtils.UnpackToRgbPlanes(redChannel, greenChannel, blueChannel, source); + } } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 9d93d27aca..beebec8283 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -165,7 +165,7 @@ public partial class PixelOperations } /// - /// Bulk operation that packs 3 seperate RGB channels to . + /// Bulk operation that packs 3 separate RGB channels to . /// The destination must have a padding of 3. /// /// A to the red values. @@ -198,7 +198,7 @@ public partial class PixelOperations /// /// Bulk operation that unpacks pixels from - /// into 3 seperate RGB channels. The destination must have a padding of 3. + /// into 3 separate RGB channels. /// /// A to the red values. /// A to the green values. @@ -210,7 +210,9 @@ public partial class PixelOperations Span blueChannel, ReadOnlySpan source) { - int count = redChannel.Length; + GuardUnpackIntoRgbPlanes(redChannel, greenChannel, blueChannel, source); + + int count = source.Length; Rgba32 rgba32 = default; @@ -227,6 +229,14 @@ public partial class PixelOperations } } + [MethodImpl(InliningOptions.ShortMethod)] + internal static void GuardUnpackIntoRgbPlanes(Span redChannel, Span greenChannel, Span blueChannel, ReadOnlySpan source) + { + Guard.IsTrue(greenChannel.Length == redChannel.Length, nameof(greenChannel), "Channels must be of same size!"); + Guard.IsTrue(blueChannel.Length == redChannel.Length, nameof(blueChannel), "Channels must be of same size!"); + Guard.IsTrue(source.Length <= redChannel.Length, nameof(source), "'source' span should not be bigger than the destination channels!"); + } + [MethodImpl(InliningOptions.ShortMethod)] internal static void GuardPackFromRgbPlanes(ReadOnlySpan greenChannel, ReadOnlySpan blueChannel, Span destination, int count) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs index aed84a7d92..5842c8e1a0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.cs @@ -3,6 +3,7 @@ using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -87,7 +88,7 @@ public partial class JpegEncoderTests { using Image image = provider.GetImage(); - var encoder = new JpegEncoder + JpegEncoder encoder = new() { Quality = quality, ColorType = colorType, @@ -164,8 +165,8 @@ public partial class JpegEncoderTests [InlineData(JpegEncodingColor.YCbCrRatio444)] public async Task Encode_IsCancellable(JpegEncodingColor colorType) { - var cts = new CancellationTokenSource(); - using var pausedStream = new PausedStream(new MemoryStream()); + CancellationTokenSource cts = new(); + using PausedStream pausedStream = new(new MemoryStream()); pausedStream.OnWaiting(s => { // after some writing @@ -181,14 +182,37 @@ public partial class JpegEncoderTests } }); - using var image = new Image(5000, 5000); + using Image image = new(5000, 5000); await Assert.ThrowsAsync(async () => { - var encoder = new JpegEncoder() { ColorType = colorType }; + JpegEncoder encoder = new() { ColorType = colorType }; await image.SaveAsync(pausedStream, encoder, cts.Token); }); } + // https://github.com/SixLabors/ImageSharp/issues/2595 + [Theory] + [WithFile(TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, PixelTypes.Bgra32)] + [WithFile(TestImages.Jpeg.Baseline.ForestBridgeDifferentComponentsQuality, PixelTypes.Rgb24)] + public static void Issue2595(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + image.Mutate(x => x.Crop(132, 1606)); + + int[] quality = new int[] { 100, 50 }; + JpegEncodingColor[] colors = new[] { JpegEncodingColor.YCbCrRatio444, JpegEncodingColor.YCbCrRatio420 }; + for (int i = 0; i < quality.Length; i++) + { + int q = quality[i]; + for (int j = 0; j < colors.Length; j++) + { + JpegEncodingColor c = colors[j]; + image.VerifyEncoder(provider, "jpeg", $"{q}-{c}", new JpegEncoder() { Quality = q, ColorType = c }, GetComparer(q, c)); + } + } + } + /// /// Anton's SUPER-SCIENTIFIC tolerance threshold calculation /// @@ -225,7 +249,7 @@ public partial class JpegEncoderTests { using Image image = provider.GetImage(); - var encoder = new JpegEncoder + JpegEncoder encoder = new() { Quality = quality, ColorType = colorType From d79e08c6dae35d9fae18a7e5e63ee266e98bcc3a Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Fri, 1 Dec 2023 14:31:18 +0100 Subject: [PATCH 079/219] Update to latest SharedInfrastructure commit --- shared-infrastructure | 2 +- src/ImageSharp/ImageSharp.csproj | 1 - tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj | 1 - 3 files changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-infrastructure b/shared-infrastructure index 353b9afe32..4e892950d7 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 353b9afe32a8000410312d17263407cd7bb82d19 +Subproject commit 4e892950d7f17e5cb64160675d6902545cc3b5c5 diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index a1c7e6175f..12da6cf532 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -17,7 +17,6 @@ - 12.0 enable Nullable diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 5686003116..22a2777a6a 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -10,7 +10,6 @@ false Debug;Release - 12.0 From 651763daa705a377006eb073f45fc212a33ed950 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Fri, 1 Dec 2023 14:47:42 +0100 Subject: [PATCH 080/219] Fix SA1516 --- src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs | 1 + src/ImageSharp/Formats/AnimatedImageMetadata.cs | 1 + src/ImageSharp/Formats/Qoi/QoiDecoder.cs | 1 + 3 files changed, 3 insertions(+) diff --git a/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs index 5f4015180b..75595e1f7d 100644 --- a/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs +++ b/src/ImageSharp/Formats/AnimatedImageFrameMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats; + internal class AnimatedImageFrameMetadata { /// diff --git a/src/ImageSharp/Formats/AnimatedImageMetadata.cs b/src/ImageSharp/Formats/AnimatedImageMetadata.cs index d89ec41f07..ac3ca29f4f 100644 --- a/src/ImageSharp/Formats/AnimatedImageMetadata.cs +++ b/src/ImageSharp/Formats/AnimatedImageMetadata.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats; + internal class AnimatedImageMetadata { /// diff --git a/src/ImageSharp/Formats/Qoi/QoiDecoder.cs b/src/ImageSharp/Formats/Qoi/QoiDecoder.cs index a54095dfc6..5c1bf6ad23 100644 --- a/src/ImageSharp/Formats/Qoi/QoiDecoder.cs +++ b/src/ImageSharp/Formats/Qoi/QoiDecoder.cs @@ -4,6 +4,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Qoi; + internal class QoiDecoder : ImageDecoder { private QoiDecoder() From 98ffa0fb44040cd0e2ae4d8f922d4ee622fe7879 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Fri, 1 Dec 2023 16:26:00 +0100 Subject: [PATCH 081/219] Update Microsoft.DotNet.RemoteExecutor --- tests/Directory.Build.targets | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 3a29442872..85796e0d63 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -22,8 +22,8 @@ - - + + From 290906a752f98cdd678516f04d09467c24ce2608 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Fri, 1 Dec 2023 16:29:53 +0100 Subject: [PATCH 082/219] Fix CA1513 --- .../Allocators/Internals/SharedArrayPoolBuffer{T}.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs index c0a0c5d272..02bdf0f48d 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/SharedArrayPoolBuffer{T}.cs @@ -57,15 +57,7 @@ internal class SharedArrayPoolBuffer : ManagedBufferBase, IRefCounted [Conditional("DEBUG")] [MemberNotNull(nameof(Array))] - private void CheckDisposed() - { -#pragma warning disable CA1513 - if (this.Array == null) - { - throw new ObjectDisposedException("SharedArrayPoolBuffer"); - } -#pragma warning restore CA1513 - } + private void CheckDisposed() => ObjectDisposedException.ThrowIf(this.Array == null, this.Array); private sealed class LifetimeGuard : RefCountedMemoryLifetimeGuard { From b52ef56181615d91df24977f66fd48fa2d6ca048 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Sun, 3 Dec 2023 21:44:53 +0100 Subject: [PATCH 083/219] Promote PixelTypeInfo to TPixel Fixes #2534 --- src/ImageSharp/Formats/PixelTypeInfo.cs | 32 +-- src/ImageSharp/Image{TPixel}.cs | 8 +- src/ImageSharp/PixelFormats/IPixel.cs | 3 + .../PixelFormats/PixelImplementations/A8.cs | 3 + .../PixelImplementations/Abgr32.cs | 3 + .../PixelImplementations/Argb32.cs | 3 + .../PixelImplementations/Bgr24.cs | 3 + .../PixelImplementations/Bgr565.cs | 3 + .../PixelImplementations/Bgra32.cs | 3 + .../PixelImplementations/Bgra4444.cs | 3 + .../PixelImplementations/Bgra5551.cs | 3 + .../PixelImplementations/Byte4.cs | 3 + .../PixelImplementations/HalfSingle.cs | 3 + .../PixelImplementations/HalfVector2.cs | 3 + .../PixelImplementations/HalfVector4.cs | 3 + .../PixelFormats/PixelImplementations/L16.cs | 3 + .../PixelFormats/PixelImplementations/L8.cs | 3 + .../PixelFormats/PixelImplementations/La16.cs | 3 + .../PixelFormats/PixelImplementations/La32.cs | 3 + .../PixelImplementations/NormalizedByte2.cs | 3 + .../PixelImplementations/NormalizedByte4.cs | 3 + .../PixelImplementations/NormalizedShort2.cs | 3 + .../PixelImplementations/NormalizedShort4.cs | 3 + .../PixelOperations/A8.PixelOperations.cs | 9 +- .../PixelOperations/Abgr32.PixelOperations.cs | 9 +- .../PixelOperations/Argb32.PixelOperations.cs | 9 +- .../PixelOperations/Bgr24.PixelOperations.cs | 9 +- .../PixelOperations/Bgr565.PixelOperations.cs | 9 +- .../PixelOperations/Bgra32.PixelOperations.cs | 9 +- .../Bgra4444.PixelOperations.cs | 9 +- .../Bgra5551.PixelOperations.cs | 9 +- .../PixelOperations/Byte4.PixelOperations.cs | 9 +- .../HalfSingle.PixelOperations.cs | 9 +- .../HalfVector2.PixelOperations.cs | 9 +- .../HalfVector4.PixelOperations.cs | 9 +- .../PixelOperations/L16.PixelOperations.cs | 9 +- .../PixelOperations/L8.PixelOperations.cs | 9 +- .../PixelOperations/La16.PixelOperations.cs | 9 +- .../PixelOperations/La32.PixelOperations.cs | 9 +- .../NormalizedByte2.PixelOperations.cs | 9 +- .../NormalizedByte4.PixelOperations.cs | 9 +- .../NormalizedShort2.PixelOperations.cs | 9 +- .../NormalizedShort4.PixelOperations.cs | 9 +- .../PixelOperations/Rg32.PixelOperations.cs | 9 +- .../PixelOperations/Rgb24.PixelOperations.cs | 5 - .../PixelOperations/Rgb48.PixelOperations.cs | 9 +- .../Rgba1010102.PixelOperations.cs | 9 +- .../PixelOperations/Rgba32.PixelOperations.cs | 6 - .../PixelOperations/Rgba64.PixelOperations.cs | 9 +- .../RgbaVector.PixelOperations.cs | 6 - .../PixelOperations/Short2.PixelOperations.cs | 9 +- .../PixelOperations/Short4.PixelOperations.cs | 9 +- .../PixelFormats/PixelImplementations/Rg32.cs | 3 + .../PixelImplementations/Rgb24.cs | 3 + .../PixelImplementations/Rgb48.cs | 3 + .../PixelImplementations/Rgba1010102.cs | 3 + .../PixelImplementations/Rgba32.cs | 3 + .../PixelImplementations/Rgba64.cs | 3 + .../PixelImplementations/RgbaVector.cs | 3 + .../PixelImplementations/Short2.cs | 3 + .../PixelImplementations/Short4.cs | 3 + .../PixelFormats/PixelOperations{TPixel}.cs | 3 +- .../Resize/ResizeProcessor{TPixel}.cs | 2 +- .../Formats/Bmp/BmpDecoderTests.cs | 2 +- .../Formats/Tiff/BigTiffDecoderTests.cs | 2 +- ...elOperationsTests.Specialized.Generated.cs | 263 ++++-------------- .../Generated/_Common.ttinclude | 9 +- .../PixelOperations/PixelOperationsTests.cs | 6 +- tests/ImageSharp.Tests/TestFormat.cs | 2 + .../BasicTestPatternProvider.cs | 5 + 70 files changed, 207 insertions(+), 468 deletions(-) diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index 1328c65280..15fd0dc2a6 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Formats; /// /// Contains information about the pixels that make up an images visual data. /// -public class PixelTypeInfo +public readonly struct PixelTypeInfo { /// /// Initializes a new instance of the class. @@ -21,33 +21,25 @@ public class PixelTypeInfo public PixelTypeInfo(int bitsPerPixel) => this.BitsPerPixel = bitsPerPixel; - /// - /// Initializes a new instance of the class. - /// - /// Color depth, in number of bits per pixel. - /// The pixel alpha transparency behavior. - public PixelTypeInfo(int bitsPerPixel, PixelAlphaRepresentation alpha) - { - this.BitsPerPixel = bitsPerPixel; - this.AlphaRepresentation = alpha; - } - /// /// Gets color depth, in number of bits per pixel. /// - public int BitsPerPixel { get; } + public int BitsPerPixel { get; init; } + + public byte ComponentCount { get; init; } /// /// Gets the pixel alpha transparency behavior. /// means unknown, unspecified. /// - public PixelAlphaRepresentation? AlphaRepresentation { get; } - - internal static PixelTypeInfo Create() - where TPixel : unmanaged, IPixel - => new(Unsafe.SizeOf() * 8); + public PixelAlphaRepresentation? AlphaRepresentation { get; init; } - internal static PixelTypeInfo Create(PixelAlphaRepresentation alpha) + internal static PixelTypeInfo Create(byte componentCount, PixelAlphaRepresentation pixelAlphaRepresentation) where TPixel : unmanaged, IPixel - => new(Unsafe.SizeOf() * 8, alpha); + => new() + { + BitsPerPixel = Unsafe.SizeOf() * 8, + ComponentCount = componentCount, + AlphaRepresentation = pixelAlphaRepresentation + }; } diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index c24014e698..38f0b94d62 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -78,7 +78,7 @@ public sealed class Image : Image /// The height of the image in pixels. /// The images metadata. internal Image(Configuration configuration, int width, int height, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, default(TPixel)); /// @@ -111,7 +111,7 @@ public sealed class Image : Image int width, int height, ImageMetadata metadata) - : base(configuration, PixelTypeInfo.Create(), metadata, width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata, width, height) => this.frames = new ImageFrameCollection(this, width, height, memoryGroup); /// @@ -129,7 +129,7 @@ public sealed class Image : Image int height, TPixel backgroundColor, ImageMetadata? metadata) - : base(configuration, PixelTypeInfo.Create(), metadata ?? new(), width, height) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata ?? new(), width, height) => this.frames = new ImageFrameCollection(this, width, height, backgroundColor); /// @@ -140,7 +140,7 @@ public sealed class Image : Image /// The images metadata. /// The frames that will be owned by this image instance. internal Image(Configuration configuration, ImageMetadata metadata, IEnumerable> frames) - : base(configuration, PixelTypeInfo.Create(), metadata, ValidateFramesAndGetSize(frames)) + : base(configuration, TPixel.GetPixelTypeInfo(), metadata, ValidateFramesAndGetSize(frames)) => this.frames = new ImageFrameCollection(this, frames); /// diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 0994444668..cddf6453d9 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,6 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats; public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { + static abstract PixelTypeInfo GetPixelTypeInfo(); + /// /// Creates a instance for this pixel type. /// This method is not intended to be consumed directly. Use instead. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 0256907121..b2d99ac4be 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -55,6 +56,8 @@ public partial struct A8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(A8 left, A8 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 8bd24c7a01..7c0dba5521 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -183,6 +184,8 @@ public partial struct Abgr32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index fa8af98a0b..f09f25ab0e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -183,6 +184,8 @@ public partial struct Argb32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index aedf4ad198..499c72b8da 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -87,6 +88,8 @@ public partial struct Bgr24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index ac3b6f8299..1ac9fbddb8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -59,6 +60,8 @@ public partial struct Bgr565 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index d7222f2ef8..a689067e58 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -136,6 +137,8 @@ public partial struct Bgra32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 8ba32c8ac2..de94817d45 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -57,6 +58,8 @@ public partial struct Bgra4444 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index c282f03d89..2bfbde7c64 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -60,6 +61,8 @@ public partial struct Bgra5551 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index e699e5fe58..e1d6bdd52e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -60,6 +61,8 @@ public partial struct Byte4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index db1e02adc2..b37b7260c8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -45,6 +46,8 @@ public partial struct HalfSingle : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + /// public PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 9caae58c95..02c3433fda 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -52,6 +53,8 @@ public partial struct HalfVector2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 609fec3bd7..ee8be97c1c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -57,6 +58,8 @@ public partial struct HalfVector4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index c6ee8744d9..2b70c15635 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -47,6 +48,8 @@ public partial struct L16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L16 left, L16 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 383e09b270..df61897067 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -48,6 +49,8 @@ public partial struct L8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L8 left, L8 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 58aeb61890..97e5db9f04 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -71,6 +72,8 @@ public partial struct La16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La16 left, La16 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index db7f433293..090824a839 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -73,6 +74,8 @@ public partial struct La32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La32 left, La32 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 92b9e6148a..ba56e9ecd4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -60,6 +61,8 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index f87bb5a602..27fed194f8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -62,6 +63,8 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index f77dd69b71..55ab0888b8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -61,6 +62,8 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 989edbd2ba..0306a63293 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -63,6 +64,8 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs index a7b4b5df00..131191ee29 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct A8 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs index 66f3ecb245..17ca5edd81 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Abgr32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs index 894e92963e..f2a5eb28b0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Argb32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs index a8f6ab1556..05b198636f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Bgr24 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs index de96903256..7217b7c0b0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Bgr565 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs index 1a62b0809c..0d77f8566f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Bgra32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs index 8ffdaf6cb5..5f516f0945 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Bgra4444 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs index 97f5d805e6..ea11e53095 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Bgra5551 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs index f6e0b833c2..0946dd4c78 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Byte4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs index c8c4110c73..8343b4b3c4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct HalfSingle /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs index bdf58145fd..9a2bdd2603 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct HalfVector2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs index c3fe598045..0590b43c8e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct HalfVector4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs index 7495cee53d..fc7a81ae20 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct L16 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs index 5dd98c3a66..c97af4e347 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct L8 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs index d9bda3e0fc..9be38ac4e0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct La16 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs index 1fb5adfc8f..824618c658 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct La32 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs index 7176295869..848d0d6f3a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct NormalizedByte2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs index 9bb48f5924..79319070dc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct NormalizedByte4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs index 3913f64bb5..0b5f23bc58 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct NormalizedShort2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs index 6334f4e7e4..21634a2b34 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct NormalizedShort4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs index a5b803f768..e0e117727d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Rg32 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index 5473a602f9..f88640d9ee 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -15,11 +15,6 @@ public partial struct Rgb24 /// internal partial class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; /// internal override void PackFromRgbPlanes( diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs index 56a052a7dd..26f216ae23 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Rgb48 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs index f550396275..80c54ac2bb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Rgba1010102 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index a4887b393c..36b9f85f77 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -18,12 +18,6 @@ public partial struct Rgba32 /// internal partial class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - /// public override void ToVector4( Configuration configuration, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs index 56bbc6b25b..f796098c6d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Rgba64 /// /// Provides optimized overrides for bulk operations. /// - internal partial class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal partial class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs index a3833583fc..c18c3d8687 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs @@ -19,12 +19,6 @@ public partial struct RgbaVector /// internal class PixelOperations : PixelOperations { - private static readonly Lazy LazyInfo = - new(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - /// public override void From( Configuration configuration, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs index 435a521ba7..737cd52993 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Short2 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.None), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs index 546da9c57d..ab069c0ab1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs @@ -13,12 +13,5 @@ public partial struct Short4 /// /// Provides optimized overrides for bulk operations. /// - internal class PixelOperations : PixelOperations - { - private static readonly Lazy LazyInfo = - new Lazy(() => PixelTypeInfo.Create(PixelAlphaRepresentation.Unassociated), true); - - /// - public override PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; - } + internal class PixelOperations : PixelOperations; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 0a13a15eda..b824acad4d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -57,6 +58,8 @@ public partial struct Rg32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 105618cd96..609ad21b7b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -106,6 +107,8 @@ public partial struct Rgb24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 6bf25717ce..e89393c528 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -69,6 +70,8 @@ public partial struct Rgb48 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 7bac1d9208..734b1e2293 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -60,6 +61,8 @@ public partial struct Rgba1010102 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 75fe8f3f4e..e1be7d0ecb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -286,6 +287,8 @@ public partial struct Rgba32 : IPixel, IPackedVector return true; } + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 75235c9007..95b1f242f9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -206,6 +207,8 @@ public partial struct Rgba64 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 899987b712..c914ca9e31 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -5,6 +5,7 @@ using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -96,6 +97,8 @@ public partial struct RgbaVector : IPixel /// public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 832e8c770f..b5155c1faa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -64,6 +65,8 @@ public partial struct Short2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index c4dc324a13..3318889998 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -66,6 +67,8 @@ public partial struct Short4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index beebec8283..ee675e2e29 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -18,7 +18,6 @@ namespace SixLabors.ImageSharp.PixelFormats; public partial class PixelOperations where TPixel : unmanaged, IPixel { - private static readonly Lazy LazyInfo = new(() => PixelTypeInfo.Create(), true); private static readonly Lazy> LazyInstance = new(() => default(TPixel).CreatePixelOperations(), true); /// @@ -32,7 +31,7 @@ public partial class PixelOperations /// Gets the pixel type info for the given . /// /// The . - public virtual PixelTypeInfo GetPixelTypeInfo() => LazyInfo.Value; + public static PixelTypeInfo GetPixelTypeInfo() => TPixel.GetPixelTypeInfo(); /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 98c2523fae..38aab02839 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -197,7 +197,7 @@ internal class ResizeProcessor : TransformProcessor, IResampling bool compand, bool premultiplyAlpha) { - PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo()?.AlphaRepresentation; + PixelAlphaRepresentation? alphaRepresentation = PixelOperations.GetPixelTypeInfo().AlphaRepresentation; // Premultiply only if alpha representation is unknown or Unassociated: bool needsPremultiplication = alphaRepresentation == null || alphaRepresentation.Value == PixelAlphaRepresentation.Unassociated; diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index e76f21d0e9..78a7b2c11c 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -477,7 +477,7 @@ public class BmpDecoderTests using MemoryStream stream = new(testFile.Bytes, false); ImageInfo imageInfo = Image.Identify(stream); Assert.NotNull(imageInfo); - Assert.Equal(expectedPixelSize, imageInfo.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, imageInfo.PixelType.BitsPerPixel); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs index 8e90b1dd57..72f53cab78 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/BigTiffDecoderTests.cs @@ -65,7 +65,7 @@ public class BigTiffDecoderTests : TiffDecoderBaseTester using MemoryStream stream = new(testFile.Bytes, false); ImageInfo info = Image.Identify(stream); - Assert.Equal(expectedPixelSize, info.PixelType?.BitsPerPixel); + Assert.Equal(expectedPixelSize, info.PixelType.BitsPerPixel); Assert.Equal(expectedWidth, info.Width); Assert.Equal(expectedHeight, info.Height); Assert.NotNull(info.Metadata); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs index 5ba5c1bedf..b372829270 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/PixelOperationsTests.Specialized.Generated.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. // @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Tests.PixelFormats.PixelOperations; public partial class PixelOperationsTests { - + public partial class A8_OperationsTests : PixelOperationsTests { public A8_OperationsTests(ITestOutputHelper output) @@ -20,19 +20,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => A8.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = A8.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Argb32_OperationsTests : PixelOperationsTests { public Argb32_OperationsTests(ITestOutputHelper output) @@ -40,19 +35,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Argb32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Argb32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Abgr32_OperationsTests : PixelOperationsTests { public Abgr32_OperationsTests(ITestOutputHelper output) @@ -60,19 +50,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Abgr32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Abgr32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgr24_OperationsTests : PixelOperationsTests { public Bgr24_OperationsTests(ITestOutputHelper output) @@ -80,19 +65,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Bgr24.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgr24.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Bgr565_OperationsTests : PixelOperationsTests { public Bgr565_OperationsTests(ITestOutputHelper output) @@ -100,19 +80,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Bgr565.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgr565.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Bgra32_OperationsTests : PixelOperationsTests { public Bgra32_OperationsTests(ITestOutputHelper output) @@ -120,19 +95,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Bgra32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgra4444_OperationsTests : PixelOperationsTests { public Bgra4444_OperationsTests(ITestOutputHelper output) @@ -140,19 +110,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Bgra4444.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra4444.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Bgra5551_OperationsTests : PixelOperationsTests { public Bgra5551_OperationsTests(ITestOutputHelper output) @@ -160,19 +125,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Bgra5551.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Bgra5551.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Byte4_OperationsTests : PixelOperationsTests { public Byte4_OperationsTests(ITestOutputHelper output) @@ -180,19 +140,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Byte4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Byte4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class HalfSingle_OperationsTests : PixelOperationsTests { public HalfSingle_OperationsTests(ITestOutputHelper output) @@ -200,19 +155,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => HalfSingle.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfSingle.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class HalfVector2_OperationsTests : PixelOperationsTests { public HalfVector2_OperationsTests(ITestOutputHelper output) @@ -220,19 +170,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => HalfVector2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfVector2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class HalfVector4_OperationsTests : PixelOperationsTests { public HalfVector4_OperationsTests(ITestOutputHelper output) @@ -240,19 +185,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => HalfVector4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = HalfVector4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class L16_OperationsTests : PixelOperationsTests { public L16_OperationsTests(ITestOutputHelper output) @@ -260,19 +200,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => L16.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = L16.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class L8_OperationsTests : PixelOperationsTests { public L8_OperationsTests(ITestOutputHelper output) @@ -280,19 +215,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => L8.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = L8.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class La16_OperationsTests : PixelOperationsTests { public La16_OperationsTests(ITestOutputHelper output) @@ -300,19 +230,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => La16.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = La16.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class La32_OperationsTests : PixelOperationsTests { public La32_OperationsTests(ITestOutputHelper output) @@ -320,19 +245,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => La32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = La32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class NormalizedByte2_OperationsTests : PixelOperationsTests { public NormalizedByte2_OperationsTests(ITestOutputHelper output) @@ -340,19 +260,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => NormalizedByte2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedByte2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class NormalizedByte4_OperationsTests : PixelOperationsTests { public NormalizedByte4_OperationsTests(ITestOutputHelper output) @@ -360,19 +275,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => NormalizedByte4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedByte4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class NormalizedShort2_OperationsTests : PixelOperationsTests { public NormalizedShort2_OperationsTests(ITestOutputHelper output) @@ -380,19 +290,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => NormalizedShort2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedShort2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class NormalizedShort4_OperationsTests : PixelOperationsTests { public NormalizedShort4_OperationsTests(ITestOutputHelper output) @@ -400,19 +305,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => NormalizedShort4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = NormalizedShort4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rg32_OperationsTests : PixelOperationsTests { public Rg32_OperationsTests(ITestOutputHelper output) @@ -420,19 +320,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rg32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rg32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgb24_OperationsTests : PixelOperationsTests { public Rgb24_OperationsTests(ITestOutputHelper output) @@ -440,19 +335,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rgb24.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgb24.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgb48_OperationsTests : PixelOperationsTests { public Rgb48_OperationsTests(ITestOutputHelper output) @@ -460,19 +350,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rgb48.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgb48.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Rgba1010102_OperationsTests : PixelOperationsTests { public Rgba1010102_OperationsTests(ITestOutputHelper output) @@ -480,19 +365,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rgba1010102.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba1010102.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rgba32_OperationsTests : PixelOperationsTests { public Rgba32_OperationsTests(ITestOutputHelper output) @@ -500,19 +380,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rgba32.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba32.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Rgba64_OperationsTests : PixelOperationsTests { public Rgba64_OperationsTests(ITestOutputHelper output) @@ -520,19 +395,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Rgba64.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Rgba64.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class RgbaVector_OperationsTests : PixelOperationsTests { public RgbaVector_OperationsTests(ITestOutputHelper output) @@ -540,19 +410,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => RgbaVector.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = RgbaVector.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } - + public partial class Short2_OperationsTests : PixelOperationsTests { public Short2_OperationsTests(ITestOutputHelper output) @@ -560,19 +425,14 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Short2.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Short2.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.None, alphaRepresentation); } } - + public partial class Short4_OperationsTests : PixelOperationsTests { public Short4_OperationsTests(ITestOutputHelper output) @@ -580,15 +440,10 @@ public partial class PixelOperationsTests { } - protected override PixelOperations Operations => Short4.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType(PixelOperations.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = Short4.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(PixelAlphaRepresentation.Unassociated, alphaRepresentation); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude index 0e7b1f3354..90cb3a8665 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/Generated/_Common.ttinclude @@ -70,7 +70,7 @@ using Xunit.Abstractions; void GenerateSpecializedClass(string pixelType, string alpha) {#> - + public partial class <#=pixelType#>_OperationsTests : PixelOperationsTests<<#=pixelType#>> { public <#=pixelType#>_OperationsTests(ITestOutputHelper output) @@ -78,15 +78,10 @@ using Xunit.Abstractions; { } - protected override PixelOperations<<#=pixelType#>> Operations => <#=pixelType#>.PixelOperations.Instance; - - [Fact] - public void IsSpecialImplementation() => Assert.IsType<<#=pixelType#>.PixelOperations>(PixelOperations<<#=pixelType#>>.Instance); - [Fact] public void PixelTypeInfoHasCorrectAlphaRepresentation() { - var alphaRepresentation = this.Operations.GetPixelTypeInfo().AlphaRepresentation; + var alphaRepresentation = <#=pixelType#>.GetPixelTypeInfo().AlphaRepresentation; Assert.Equal(<#=alpha#>, alphaRepresentation); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index a9b3ee9a42..8c16a72df0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -70,7 +70,7 @@ public abstract class PixelOperationsTests : MeasureFixture protected virtual PixelOperations Operations { get; } = PixelOperations.Instance; - protected bool HasUnassociatedAlpha => this.Operations.GetPixelTypeInfo().AlphaRepresentation == PixelAlphaRepresentation.Unassociated; + protected bool HasUnassociatedAlpha => TPixel.GetPixelTypeInfo().AlphaRepresentation == PixelAlphaRepresentation.Unassociated; internal static TPixel[] CreateExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { @@ -105,7 +105,7 @@ public abstract class PixelOperationsTests : MeasureFixture [Fact] public void PixelTypeInfoHasCorrectBitsPerPixel() { - int bits = this.Operations.GetPixelTypeInfo().BitsPerPixel; + int bits = TPixel.GetPixelTypeInfo().BitsPerPixel; Assert.Equal(Unsafe.SizeOf() * 8, bits); } @@ -123,7 +123,7 @@ public abstract class PixelOperationsTests : MeasureFixture Rgba32 dest = default; pixel.ToRgba32(ref dest); - bool hasAlpha = this.Operations.GetPixelTypeInfo().AlphaRepresentation != PixelAlphaRepresentation.None; + bool hasAlpha = TPixel.GetPixelTypeInfo().AlphaRepresentation != PixelAlphaRepresentation.None; byte expectedAlpha = hasAlpha ? Alpha : NoAlpha; Assert.Equal(expectedAlpha, dest.A); diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index f597b708d5..465a219701 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -263,6 +263,8 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public struct TestPixelForAgnosticDecode : IPixel { + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public PixelOperations CreatePixelOperations() => new(); public void FromScaledVector4(Vector4 vector) diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs index 1e3ad3a5d5..5fb3501e36 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs @@ -8,6 +8,11 @@ namespace SixLabors.ImageSharp.Tests; public abstract partial class TestImageProvider : IXunitSerializable { + [Obsolete("Called by the de-serializer; should only be called by deriving classes for de-serialization purposes")] + public TestImageProvider() + { + } + public virtual TPixel GetExpectedBasicTestPatternPixelAt(int x, int y) { throw new NotSupportedException("GetExpectedBasicTestPatternPixelAt(x,y) only works with BasicTestPattern"); From 9ac4cd91a417fa28bbb6357e1e82f63a40cab1d9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 4 Dec 2023 12:33:35 +1000 Subject: [PATCH 084/219] Enable CA1859 --- .gitattributes | 3 +++ shared-infrastructure | 2 +- src/ImageSharp.ruleset | 3 --- src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs | 4 ++-- src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs | 2 +- src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs | 2 +- 6 files changed, 8 insertions(+), 8 deletions(-) diff --git a/.gitattributes b/.gitattributes index 3647a7063d..b5f742ab47 100644 --- a/.gitattributes +++ b/.gitattributes @@ -133,3 +133,6 @@ *.pnm filter=lfs diff=lfs merge=lfs -text *.wbmp filter=lfs diff=lfs merge=lfs -text *.exr filter=lfs diff=lfs merge=lfs -text +*.ico filter=lfs diff=lfs merge=lfs -text +*.cur filter=lfs diff=lfs merge=lfs -text +*.ani filter=lfs diff=lfs merge=lfs -text diff --git a/shared-infrastructure b/shared-infrastructure index 4e892950d7..1c526a97ee 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 4e892950d7f17e5cb64160675d6902545cc3b5c5 +Subproject commit 1c526a97eea8bcbc7c79de095676f7fb975a9fb1 diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index 8327dd7565..d7a147df03 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,9 +1,6 @@  - - - diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs index c3cd95c028..f251df3bf2 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegFrame.cs @@ -133,7 +133,7 @@ internal sealed class JpegFrame : IDisposable for (int i = 0; i < this.ComponentCount; i++) { - IJpegComponent component = this.Components[i]; + JpegComponent component = this.Components[i]; component.Init(maxSubFactorH, maxSubFactorV); } } @@ -143,7 +143,7 @@ internal sealed class JpegFrame : IDisposable bool fullScan = this.Progressive || !this.Interleaved; for (int i = 0; i < this.ComponentCount; i++) { - IJpegComponent component = this.Components[i]; + JpegComponent component = this.Components[i]; component.AllocateSpectral(fullScan); } } diff --git a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs index 086eef0585..114fc12b23 100644 --- a/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs +++ b/src/ImageSharp/Formats/Tiff/Ifd/DirectoryReader.cs @@ -71,7 +71,7 @@ internal class DirectoryReader throw TiffThrowHelper.ThrowInvalidHeader(); } - private IList ReadIfds(bool isBigTiff) + private List ReadIfds(bool isBigTiff) { List readers = new(); while (this.nextIfdOffset != 0 && this.nextIfdOffset < (ulong)this.stream.Length) diff --git a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs index 953ef74afb..a4fcd9275b 100644 --- a/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs +++ b/src/ImageSharp/Metadata/Profiles/Exif/ExifReader.cs @@ -472,7 +472,7 @@ internal abstract class BaseExifReader } } - private void Add(IList values, IExifValue exif, object? value) + private void Add(IList values, ExifValue exif, object? value) { if (!exif.TrySetValue(value)) { From b4f9bf963bc67a52257d7ac04a9d802073f69ac0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 4 Dec 2023 14:58:01 +1000 Subject: [PATCH 085/219] Update package dependencies and min ver number --- src/ImageSharp/ImageSharp.csproj | 4 ++-- tests/Directory.Build.targets | 20 +++++++++---------- .../ImageSharp.Benchmarks.csproj | 4 ++-- .../LoadResizeSaveStressRunner.cs | 6 ++---- .../ImageSharp.Tests.ProfilingSandbox.csproj | 2 +- .../ImageSharp.Tests/ImageSharp.Tests.csproj | 6 +++++- 6 files changed, 21 insertions(+), 21 deletions(-) diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 12da6cf532..4c08fc017b 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -22,8 +22,8 @@ - - 3.1 + + 4.0 diff --git a/tests/Directory.Build.targets b/tests/Directory.Build.targets index 85796e0d63..d6b35d003f 100644 --- a/tests/Directory.Build.targets +++ b/tests/Directory.Build.targets @@ -18,20 +18,18 @@ - - - - + + - - - - - - + + + + + + - + diff --git a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj index 22a2777a6a..4408159ef4 100644 --- a/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj +++ b/tests/ImageSharp.Benchmarks/ImageSharp.Benchmarks.csproj @@ -41,8 +41,8 @@ - - + + diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs index dd9b55e58d..a06784f1b1 100644 --- a/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs +++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/LoadResizeSaveStressRunner.cs @@ -269,9 +269,7 @@ public class LoadResizeSaveStressRunner Width = this.ThumbnailSize, Height = this.ThumbnailSize, ResizeMode = CropScaleMode.Max, - SaveFormat = FileFormat.Jpeg, - JpegQuality = Quality, - JpegSubsampleMode = ChromaSubsampleMode.Subsample420 + EncoderOptions = new JpegEncoderOptions(Quality, ChromaSubsampleMode.Subsample420, true) }; // TODO: Is there a way to capture input dimensions for IncreaseTotalMegapixels? @@ -343,6 +341,6 @@ public class LoadResizeSaveStressRunner using var thumb = NetVipsImage.Thumbnail(input, this.ThumbnailSize, this.ThumbnailSize); // Save the results - thumb.Jpegsave(this.OutputPath(input), q: Quality, strip: true); + thumb.Jpegsave(this.OutputPath(input), q: Quality, keep: NetVips.Enums.ForeignKeep.None); } } diff --git a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj index 76891b4bbb..b93d011910 100644 --- a/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj +++ b/tests/ImageSharp.Tests.ProfilingSandbox/ImageSharp.Tests.ProfilingSandbox.csproj @@ -43,7 +43,7 @@ - + diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index 491c4da872..e0c65475af 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -35,7 +35,11 @@ - + + From 2bf8d78f0fd7fd38f95f5cf99b2e0c9e01554b98 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Mon, 4 Dec 2023 10:52:24 +0100 Subject: [PATCH 086/219] Fix Analyzer errors --- src/ImageSharp.ruleset | 3 +++ src/ImageSharp/Formats/PixelTypeInfo.cs | 5 ++++- src/ImageSharp/PixelFormats/IPixel.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/A8.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs | 4 ++++ .../PixelFormats/PixelImplementations/HalfSingle.cs | 4 ++++ .../PixelFormats/PixelImplementations/HalfVector2.cs | 4 ++++ .../PixelFormats/PixelImplementations/HalfVector4.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/L16.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/L8.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/La16.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/La32.cs | 4 ++++ .../PixelFormats/PixelImplementations/NormalizedByte2.cs | 4 ++++ .../PixelFormats/PixelImplementations/NormalizedByte4.cs | 4 ++++ .../PixelFormats/PixelImplementations/NormalizedShort2.cs | 4 ++++ .../PixelFormats/PixelImplementations/NormalizedShort4.cs | 4 ++++ .../PixelOperations/Rgb24.PixelOperations.cs | 1 - src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs | 4 ++++ .../PixelFormats/PixelImplementations/Rgba1010102.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs | 4 ++++ .../PixelFormats/PixelImplementations/RgbaVector.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs | 4 ++++ src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs | 4 ++++ 33 files changed, 127 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index d7a147df03..856838ade4 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,6 +1,9 @@  + + + diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index 15fd0dc2a6..ba26e48ee6 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Formats; public readonly struct PixelTypeInfo { /// - /// Initializes a new instance of the class. + /// Initializes a new instance of the struct. /// /// Color depth, in number of bits per pixel. public PixelTypeInfo(int bitsPerPixel) @@ -26,6 +26,9 @@ public readonly struct PixelTypeInfo /// public int BitsPerPixel { get; init; } + /// + /// Gets the count of the color components + /// public byte ComponentCount { get; init; } /// diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index cddf6453d9..ed02bc9178 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -15,6 +15,10 @@ namespace SixLabors.ImageSharp.PixelFormats; public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo static abstract PixelTypeInfo GetPixelTypeInfo(); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index b2d99ac4be..8a641da4ba 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -56,6 +56,10 @@ public partial struct A8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(A8 left, A8 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 7c0dba5521..692258add0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -184,6 +184,10 @@ public partial struct Abgr32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index f09f25ab0e..1ed505ce0e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -184,6 +184,10 @@ public partial struct Argb32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 499c72b8da..16f3a3aa37 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -88,6 +88,10 @@ public partial struct Bgr24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 1ac9fbddb8..76ba91d26a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -60,6 +60,10 @@ public partial struct Bgr565 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index a689067e58..33b5cbdf8f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -137,6 +137,10 @@ public partial struct Bgra32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index de94817d45..551f9ae8b7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -58,6 +58,10 @@ public partial struct Bgra4444 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 2bfbde7c64..2477fd0175 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -61,6 +61,10 @@ public partial struct Bgra5551 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index e1d6bdd52e..de35a345ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -61,6 +61,10 @@ public partial struct Byte4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index b37b7260c8..f1a8c175c8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -46,6 +46,10 @@ public partial struct HalfSingle : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 02c3433fda..5a0bdb4370 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -53,6 +53,10 @@ public partial struct HalfVector2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index ee8be97c1c..0f40594619 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -58,6 +58,10 @@ public partial struct HalfVector4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 2b70c15635..f9ec88f8ee 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -48,6 +48,10 @@ public partial struct L16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L16 left, L16 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index df61897067..5b3b8934bf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -49,6 +49,10 @@ public partial struct L8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L8 left, L8 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 97e5db9f04..5d72818ac8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -72,6 +72,10 @@ public partial struct La16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La16 left, La16 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 090824a839..1cf04d157e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -74,6 +74,10 @@ public partial struct La32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La32 left, La32 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index ba56e9ecd4..f843d27817 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -61,6 +61,10 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 27fed194f8..a3266437dc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -63,6 +63,10 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 55ab0888b8..2049acf3f2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -62,6 +62,10 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 0306a63293..b80ad0a747 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -64,6 +64,10 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index f88640d9ee..b4dd4fcc3e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -15,7 +15,6 @@ public partial struct Rgb24 /// internal partial class PixelOperations : PixelOperations { - /// internal override void PackFromRgbPlanes( ReadOnlySpan redChannel, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index b824acad4d..074acf911b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -58,6 +58,10 @@ public partial struct Rg32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 609ad21b7b..f4350c7864 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -107,6 +107,10 @@ public partial struct Rgb24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index e89393c528..64cbfc0466 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -70,6 +70,10 @@ public partial struct Rgb48 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 734b1e2293..305144863f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -61,6 +61,10 @@ public partial struct Rgba1010102 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index e1be7d0ecb..a6267d7713 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -287,6 +287,10 @@ public partial struct Rgba32 : IPixel, IPackedVector return true; } + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 95b1f242f9..e564b26f72 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -207,6 +207,10 @@ public partial struct Rgba64 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index c914ca9e31..41f5648618 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -97,6 +97,10 @@ public partial struct RgbaVector : IPixel /// public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index b5155c1faa..015d334bda 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -65,6 +65,10 @@ public partial struct Short2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 3318889998..2c85a8d774 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -67,6 +67,10 @@ public partial struct Short4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); + /// + /// Gets the The pixel type information. + /// + /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// From 4b69d06a4b02a3cdc04304438a901de3a8adf83d Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Tue, 5 Dec 2023 06:56:35 +0100 Subject: [PATCH 087/219] Made GetPixelTypeInfo non static --- src/ImageSharp.ruleset | 3 --- src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs | 2 +- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index 856838ade4..d7a147df03 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,9 +1,6 @@  - - - diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index ee675e2e29..cf3707f9e5 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -31,7 +31,7 @@ public partial class PixelOperations /// Gets the pixel type info for the given . /// /// The . - public static PixelTypeInfo GetPixelTypeInfo() => TPixel.GetPixelTypeInfo(); + public PixelTypeInfo GetPixelTypeInfo() => TPixel.GetPixelTypeInfo(); /// /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. From 2949655d92a8b18f16a7192ad2b5c715297b9386 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Tue, 5 Dec 2023 07:02:53 +0100 Subject: [PATCH 088/219] Fix typos --- src/ImageSharp/PixelFormats/IPixel.cs | 6 ++++-- src/ImageSharp/PixelFormats/PixelImplementations/A8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs | 2 +- .../PixelFormats/PixelImplementations/Bgra4444.cs | 2 +- .../PixelFormats/PixelImplementations/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs | 2 +- .../PixelFormats/PixelImplementations/HalfSingle.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector2.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs | 2 +- .../PixelFormats/PixelImplementations/Rgba1010102.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs | 2 +- .../PixelFormats/PixelImplementations/RgbaVector.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs | 2 +- 30 files changed, 33 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index ed02bc9178..adbf688612 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -16,10 +16,12 @@ public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// - /// PixelTypeInfo + /// The . +#pragma warning disable CA1000 static abstract PixelTypeInfo GetPixelTypeInfo(); +#pragma warning restore CA1000 /// /// Creates a instance for this pixel type. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 8a641da4ba..0dc88ac90c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -57,7 +57,7 @@ public partial struct A8 : IPixel, IPackedVector public static bool operator !=(A8 left, A8 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 692258add0..1abf3e79fb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -185,7 +185,7 @@ public partial struct Abgr32 : IPixel, IPackedVector public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 1ed505ce0e..b5717c052d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -185,7 +185,7 @@ public partial struct Argb32 : IPixel, IPackedVector public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 16f3a3aa37..05d995a4e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -89,7 +89,7 @@ public partial struct Bgr24 : IPixel public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 76ba91d26a..14a690a0cc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -61,7 +61,7 @@ public partial struct Bgr565 : IPixel, IPackedVector public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 33b5cbdf8f..d97f4025ac 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -138,7 +138,7 @@ public partial struct Bgra32 : IPixel, IPackedVector public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 551f9ae8b7..15f84a604b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -59,7 +59,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 2477fd0175..109e52d4c6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -62,7 +62,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index de35a345ec..f900b49d74 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -62,7 +62,7 @@ public partial struct Byte4 : IPixel, IPackedVector public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index f1a8c175c8..42ba1a3097 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -47,7 +47,7 @@ public partial struct HalfSingle : IPixel, IPackedVector public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 5a0bdb4370..b9feee5199 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -54,7 +54,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 0f40594619..597fa6c46f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -59,7 +59,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index f9ec88f8ee..807ff0f0c4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -49,7 +49,7 @@ public partial struct L16 : IPixel, IPackedVector public static bool operator !=(L16 left, L16 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 5b3b8934bf..999a6f2d10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -50,7 +50,7 @@ public partial struct L8 : IPixel, IPackedVector public static bool operator !=(L8 left, L8 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 5d72818ac8..70d1e37d7f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -73,7 +73,7 @@ public partial struct La16 : IPixel, IPackedVector public static bool operator !=(La16 left, La16 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 1cf04d157e..2d303525dd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -75,7 +75,7 @@ public partial struct La32 : IPixel, IPackedVector public static bool operator !=(La32 left, La32 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index f843d27817..e81db6c1ad 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -62,7 +62,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index a3266437dc..79f6f15f5f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -64,7 +64,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 2049acf3f2..0e4746ca60 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -63,7 +63,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index b80ad0a747..a7d470eff5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -65,7 +65,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 074acf911b..2a52bd33e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -59,7 +59,7 @@ public partial struct Rg32 : IPixel, IPackedVector public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index f4350c7864..4f7cc0d105 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -108,7 +108,7 @@ public partial struct Rgb24 : IPixel public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 64cbfc0466..20463ca2f0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -71,7 +71,7 @@ public partial struct Rgb48 : IPixel public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 305144863f..740f44c85b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -62,7 +62,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index a6267d7713..39054e06d6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -288,7 +288,7 @@ public partial struct Rgba32 : IPixel, IPackedVector } /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index e564b26f72..d013e3fd53 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -208,7 +208,7 @@ public partial struct Rgba64 : IPixel, IPackedVector public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 41f5648618..fd30103c96 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -98,7 +98,7 @@ public partial struct RgbaVector : IPixel public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 015d334bda..697cc78a20 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -66,7 +66,7 @@ public partial struct Short2 : IPixel, IPackedVector public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 2c85a8d774..9c205eeef3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -68,7 +68,7 @@ public partial struct Short4 : IPixel, IPackedVector public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// - /// Gets the The pixel type information. + /// Gets the pixel type information. /// /// PixelTypeInfo public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); From 6cbbb19a86a816f11b32e9a7f54cb7a457a72ebf Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Tue, 5 Dec 2023 07:08:23 +0100 Subject: [PATCH 089/219] Fix usage of static method in ResizeProcessor --- .../Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs index 38aab02839..cfc30edc0f 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeProcessor{TPixel}.cs @@ -197,7 +197,7 @@ internal class ResizeProcessor : TransformProcessor, IResampling bool compand, bool premultiplyAlpha) { - PixelAlphaRepresentation? alphaRepresentation = PixelOperations.GetPixelTypeInfo().AlphaRepresentation; + PixelAlphaRepresentation? alphaRepresentation = PixelOperations.Instance.GetPixelTypeInfo().AlphaRepresentation; // Premultiply only if alpha representation is unknown or Unassociated: bool needsPremultiplication = alphaRepresentation == null || alphaRepresentation.Value == PixelAlphaRepresentation.Unassociated; From 0b2cf3200d0ecd60484345a32ad345b32a893b58 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Tue, 5 Dec 2023 07:08:38 +0100 Subject: [PATCH 090/219] Replaced comment with /// --- src/ImageSharp/PixelFormats/PixelImplementations/A8.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs | 5 +---- .../PixelFormats/PixelImplementations/HalfSingle.cs | 5 +---- .../PixelFormats/PixelImplementations/HalfVector2.cs | 5 +---- .../PixelFormats/PixelImplementations/HalfVector4.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/L16.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/L8.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/La16.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/La32.cs | 5 +---- .../PixelFormats/PixelImplementations/NormalizedByte2.cs | 5 +---- .../PixelFormats/PixelImplementations/NormalizedByte4.cs | 5 +---- .../PixelFormats/PixelImplementations/NormalizedShort2.cs | 5 +---- .../PixelFormats/PixelImplementations/NormalizedShort4.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs | 5 +---- .../PixelFormats/PixelImplementations/Rgba1010102.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs | 5 +---- .../PixelFormats/PixelImplementations/RgbaVector.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs | 5 +---- src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs | 5 +---- 29 files changed, 29 insertions(+), 116 deletions(-) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 0dc88ac90c..7662495ff7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -56,10 +56,7 @@ public partial struct A8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(A8 left, A8 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 1abf3e79fb..8fae07aa14 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -184,10 +184,7 @@ public partial struct Abgr32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index b5717c052d..9f36e31b8e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -184,10 +184,7 @@ public partial struct Argb32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 05d995a4e5..4a6caa4ce5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -88,10 +88,7 @@ public partial struct Bgr24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 14a690a0cc..564a0c53f8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -60,10 +60,7 @@ public partial struct Bgr565 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index d97f4025ac..afd6c395ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -137,10 +137,7 @@ public partial struct Bgra32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 15f84a604b..81f37c5543 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -58,10 +58,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 109e52d4c6..c80af59b34 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -61,10 +61,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index f900b49d74..6efbc96237 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -61,10 +61,7 @@ public partial struct Byte4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 42ba1a3097..8d658b2401 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -46,10 +46,7 @@ public partial struct HalfSingle : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index b9feee5199..faec2b0695 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -53,10 +53,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 597fa6c46f..e9a364ed10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -58,10 +58,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 807ff0f0c4..63c1c63c50 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -48,10 +48,7 @@ public partial struct L16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L16 left, L16 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 999a6f2d10..cc834fefee 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -49,10 +49,7 @@ public partial struct L8 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(L8 left, L8 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 70d1e37d7f..53f14d16bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -72,10 +72,7 @@ public partial struct La16 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La16 left, La16 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 2d303525dd..ab542c4dc2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -74,10 +74,7 @@ public partial struct La32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(La32 left, La32 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index e81db6c1ad..bb5238985c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -61,10 +61,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 79f6f15f5f..3bc7967953 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -63,10 +63,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 0e4746ca60..17aecfbce7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -62,10 +62,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index a7d470eff5..6bd7c140b1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -64,10 +64,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 2a52bd33e5..3f624df4a0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -58,10 +58,7 @@ public partial struct Rg32 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 4f7cc0d105..ebb0e4eac0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -107,10 +107,7 @@ public partial struct Rgb24 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 20463ca2f0..89f6e32db4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -70,10 +70,7 @@ public partial struct Rgb48 : IPixel [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 740f44c85b..9ed14aaad9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -61,10 +61,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 39054e06d6..af149e3921 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -287,10 +287,7 @@ public partial struct Rgba32 : IPixel, IPackedVector return true; } - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index d013e3fd53..a214071742 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -207,10 +207,7 @@ public partial struct Rgba64 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index fd30103c96..12f7ff2677 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -97,10 +97,7 @@ public partial struct RgbaVector : IPixel /// public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 697cc78a20..e5bbeb37ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -65,10 +65,7 @@ public partial struct Short2 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 9c205eeef3..c01c4394c0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -67,10 +67,7 @@ public partial struct Short4 : IPixel, IPackedVector [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); - /// - /// Gets the pixel type information. - /// - /// PixelTypeInfo + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); /// From 153ccc312eb1f0b8cc8645a84d3aa06081bd1bd2 Mon Sep 17 00:00:00 2001 From: Stefan Nikolei Date: Wed, 6 Dec 2023 08:42:00 +0100 Subject: [PATCH 091/219] Disable SA1648 and add Ruleset to solution --- ImageSharp.sln | 1 + src/ImageSharp.ruleset | 1 + 2 files changed, 2 insertions(+) diff --git a/ImageSharp.sln b/ImageSharp.sln index 2967acb8ff..b8204c47d1 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -38,6 +38,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "src", "src", "{815C0625-CD3 src\Directory.Build.props = src\Directory.Build.props src\Directory.Build.targets = src\Directory.Build.targets src\README.md = src\README.md + src\ImageSharp.ruleset = src\ImageSharp.ruleset EndProjectSection EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "ImageSharp", "src\ImageSharp\ImageSharp.csproj", "{2AA31A1F-142C-43F4-8687-09ABCA4B3A26}" diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index d7a147df03..6c291bfb12 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -3,5 +3,6 @@ + From f3ff11ea6b9f36c1cbdf9965c0366ef97a120906 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Dec 2023 10:52:56 +1000 Subject: [PATCH 092/219] Handle dedup of local palette of 256 length --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 40 +++++++++++++++---- .../Formats/Gif/MetadataExtensions.cs | 10 ++++- .../Formats/Webp/BitReader/Vp8LBitReader.cs | 4 +- tests/ImageSharp.Tests/TestImages.cs | 4 +- tests/Images/Input/Gif/18-bit_RGB_Cube.gif | 3 ++ 5 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 tests/Images/Input/Gif/18-bit_RGB_Cube.gif diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index f0e1aafd7d..9988848d11 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -380,18 +380,42 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // We can use the color data from the decoded metadata here. // We avoid dithering by default to preserve the original colors. ReadOnlyMemory palette = metadata.LocalColorTable.Value; - if (hasDuplicates && !metadata.HasTransparency) { - // A difference was captured but the metadata does not have transparency. + // Duplicates were captured but the metadata does not have transparency. metadata.HasTransparency = true; - transparencyIndex = palette.Length; - metadata.TransparencyIndex = ClampIndex(transparencyIndex); - } - PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); - using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); - quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + if (palette.Length < 256) + { + // We can use the existing palette and set the transparent index as the length. + // decoders will ignore this value. + transparencyIndex = palette.Length; + metadata.TransparencyIndex = ClampIndex(transparencyIndex); + + PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + } + else + { + // We must quantize the frame to generate a local color table. + IQuantizer quantizer = this.hasQuantizer ? this.quantizer! : KnownQuantizers.Octree; + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + + // The transparency index derived by the quantizer will differ from the index + // within the metadata. We need to update the metadata to reflect this. + int derivedTransparencyIndex = GetTransparentIndex(quantized, null); + metadata.TransparencyIndex = ClampIndex(derivedTransparencyIndex); + } + } + else + { + // Just use the local palette. + PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + } } else { diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 16f788e3db..42602f2c78 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -77,14 +77,20 @@ public static partial class MetadataExtensions } internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source) - => new() + { + // For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or + // has a local palette with 256 colors and is not transparent we should use 'Source'. + bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency); + + return new() { ColorTable = source.LocalColorTable, ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), DisposalMode = GetMode(source.DisposalMethod), - BlendMode = source.DisposalMethod == GifDisposalMethod.RestoreToBackground ? FrameBlendMode.Source : FrameBlendMode.Over, + BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over, }; + } private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch { diff --git a/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs b/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs index 659576cf11..6d3cab1514 100644 --- a/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs +++ b/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs @@ -71,7 +71,7 @@ internal class Vp8LBitReader : BitReaderBase this.Eos = false; ulong currentValue = 0; - System.Span dataSpan = this.Data.Memory.Span; + Span dataSpan = this.Data.Memory.Span; for (int i = 0; i < 8; i++) { currentValue |= (ulong)dataSpan[i] << (8 * i); @@ -103,7 +103,7 @@ internal class Vp8LBitReader : BitReaderBase } ulong currentValue = 0; - System.Span dataSpan = this.Data.Memory.Span; + Span dataSpan = this.Data.Memory.Span; for (int i = 0; i < length; i++) { currentValue |= (ulong)dataSpan[i] << (8 * i); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 7e862f7d4f..b628529028 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -487,6 +487,7 @@ public static class TestImages public const string GlobalQuantizationTest = "Gif/GlobalQuantizationTest.gif"; public const string MixedDisposal = "Gif/mixed-disposal.gif"; public const string M4nb = "Gif/m4nb.gif"; + public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -533,7 +534,8 @@ public static class TestImages Issues.Issue2450_A, Issues.Issue2450_B, Issues.BadDescriptorWidth, - Issues.Issue1530 + Issues.Issue1530, + Bit18RGBCube }; } diff --git a/tests/Images/Input/Gif/18-bit_RGB_Cube.gif b/tests/Images/Input/Gif/18-bit_RGB_Cube.gif new file mode 100644 index 0000000000..5446661b41 --- /dev/null +++ b/tests/Images/Input/Gif/18-bit_RGB_Cube.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5148c8c192385966ec6ad5b3d35195a878355d71146a958e5ef02b7642a4e883 +size 4311986 From bec2c385f36321abf5059fb40bde7e85937d0825 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Dec 2023 06:45:27 +1000 Subject: [PATCH 093/219] Handle dedup of local palette of 256 length (#2607) --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 40 +++++++++++++++---- .../Formats/Gif/MetadataExtensions.cs | 10 ++++- .../Formats/Webp/BitReader/Vp8LBitReader.cs | 4 +- tests/ImageSharp.Tests/TestImages.cs | 4 +- tests/Images/Input/Gif/18-bit_RGB_Cube.gif | 3 ++ 5 files changed, 48 insertions(+), 13 deletions(-) create mode 100644 tests/Images/Input/Gif/18-bit_RGB_Cube.gif diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index f0e1aafd7d..9988848d11 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -380,18 +380,42 @@ internal sealed class GifEncoderCore : IImageEncoderInternals // We can use the color data from the decoded metadata here. // We avoid dithering by default to preserve the original colors. ReadOnlyMemory palette = metadata.LocalColorTable.Value; - if (hasDuplicates && !metadata.HasTransparency) { - // A difference was captured but the metadata does not have transparency. + // Duplicates were captured but the metadata does not have transparency. metadata.HasTransparency = true; - transparencyIndex = palette.Length; - metadata.TransparencyIndex = ClampIndex(transparencyIndex); - } - PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); - using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); - quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + if (palette.Length < 256) + { + // We can use the existing palette and set the transparent index as the length. + // decoders will ignore this value. + transparencyIndex = palette.Length; + metadata.TransparencyIndex = ClampIndex(transparencyIndex); + + PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + } + else + { + // We must quantize the frame to generate a local color table. + IQuantizer quantizer = this.hasQuantizer ? this.quantizer! : KnownQuantizers.Octree; + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + + // The transparency index derived by the quantizer will differ from the index + // within the metadata. We need to update the metadata to reflect this. + int derivedTransparencyIndex = GetTransparentIndex(quantized, null); + metadata.TransparencyIndex = ClampIndex(derivedTransparencyIndex); + } + } + else + { + // Just use the local palette. + PaletteQuantizer quantizer = new(palette, new() { Dither = null }, transparencyIndex); + using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(this.configuration, quantizer.Options); + quantized = frameQuantizer.BuildPaletteAndQuantizeFrame(encodingFrame, bounds); + } } else { diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 16f788e3db..42602f2c78 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -77,14 +77,20 @@ public static partial class MetadataExtensions } internal static AnimatedImageFrameMetadata ToAnimatedImageFrameMetadata(this GifFrameMetadata source) - => new() + { + // For most scenarios we would consider the blend method to be 'Over' however if a frame has a disposal method of 'RestoreToBackground' or + // has a local palette with 256 colors and is not transparent we should use 'Source'. + bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency); + + return new() { ColorTable = source.LocalColorTable, ColorTableMode = source.ColorTableMode == GifColorTableMode.Global ? FrameColorTableMode.Global : FrameColorTableMode.Local, Duration = TimeSpan.FromMilliseconds(source.FrameDelay * 10), DisposalMode = GetMode(source.DisposalMethod), - BlendMode = source.DisposalMethod == GifDisposalMethod.RestoreToBackground ? FrameBlendMode.Source : FrameBlendMode.Over, + BlendMode = blendSource ? FrameBlendMode.Source : FrameBlendMode.Over, }; + } private static FrameDisposalMode GetMode(GifDisposalMethod method) => method switch { diff --git a/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs b/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs index 659576cf11..6d3cab1514 100644 --- a/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs +++ b/src/ImageSharp/Formats/Webp/BitReader/Vp8LBitReader.cs @@ -71,7 +71,7 @@ internal class Vp8LBitReader : BitReaderBase this.Eos = false; ulong currentValue = 0; - System.Span dataSpan = this.Data.Memory.Span; + Span dataSpan = this.Data.Memory.Span; for (int i = 0; i < 8; i++) { currentValue |= (ulong)dataSpan[i] << (8 * i); @@ -103,7 +103,7 @@ internal class Vp8LBitReader : BitReaderBase } ulong currentValue = 0; - System.Span dataSpan = this.Data.Memory.Span; + Span dataSpan = this.Data.Memory.Span; for (int i = 0; i < length; i++) { currentValue |= (ulong)dataSpan[i] << (8 * i); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 7e862f7d4f..b628529028 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -487,6 +487,7 @@ public static class TestImages public const string GlobalQuantizationTest = "Gif/GlobalQuantizationTest.gif"; public const string MixedDisposal = "Gif/mixed-disposal.gif"; public const string M4nb = "Gif/m4nb.gif"; + public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -533,7 +534,8 @@ public static class TestImages Issues.Issue2450_A, Issues.Issue2450_B, Issues.BadDescriptorWidth, - Issues.Issue1530 + Issues.Issue1530, + Bit18RGBCube }; } diff --git a/tests/Images/Input/Gif/18-bit_RGB_Cube.gif b/tests/Images/Input/Gif/18-bit_RGB_Cube.gif new file mode 100644 index 0000000000..5446661b41 --- /dev/null +++ b/tests/Images/Input/Gif/18-bit_RGB_Cube.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:5148c8c192385966ec6ad5b3d35195a878355d71146a958e5ef02b7642a4e883 +size 4311986 From 5c13ca7fa7ab53da21893958e601d755132a45b6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Dec 2023 19:46:32 +1000 Subject: [PATCH 094/219] Replace Crc32, fix benchmarks --- src/ImageSharp/Compression/Zlib/Crc32.Lut.cs | 69 ---- src/ImageSharp/Compression/Zlib/Crc32.cs | 308 ------------------ ...on-generic-polynomials-pclmulqdq-paper.pdf | Bin 384202 -> 0 bytes src/ImageSharp/Formats/Png/PngDecoderCore.cs | 8 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 15 +- src/ImageSharp/ImageSharp.csproj | 4 + .../ImageSharp.Benchmarks/Bulk/FromVector4.cs | 2 +- .../Bulk/FromVector4_Rgb24.cs | 2 +- .../Bulk/ToVector4_Bgra32.cs | 2 +- .../Bulk/ToVector4_Rgb24.cs | 2 +- .../Codecs/Bmp/DecodeBmp.cs | 2 +- .../Codecs/Bmp/EncodeBmp.cs | 2 +- .../Codecs/Bmp/EncodeBmpMultiple.cs | 2 +- .../Codecs/Gif/DecodeGif.cs | 2 +- .../Codecs/Gif/EncodeGif.cs | 2 +- .../Codecs/Gif/EncodeGifMultiple.cs | 2 +- .../ColorConversion/CmykColorConversion.cs | 2 +- .../GrayscaleColorConversion.cs | 2 +- .../ColorConversion/RgbColorConversion.cs | 2 +- .../ColorConversion/YCbCrColorConversion.cs | 2 +- .../ColorConversion/YccKColorConverter.cs | 2 +- .../Codecs/Jpeg/DecodeJpegParseStreamOnly.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg_Aggregate.cs | 2 +- .../Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs | 2 +- .../Codecs/Jpeg/IdentifyJpeg.cs | 2 +- .../Codecs/Png/DecodeFilteredPng.cs | 2 +- .../Codecs/Png/DecodePng.cs | 2 +- .../Codecs/Png/EncodeIndexedPng.cs | 2 +- .../Codecs/Png/EncodePng.cs | 2 +- .../Codecs/Tga/DecodeTga.cs | 2 +- .../Codecs/Tga/EncodeTga.cs | 2 +- .../Codecs/Tiff/DecodeTiff.cs | 2 +- .../Codecs/Tiff/EncodeTiff.cs | 2 +- .../Codecs/Webp/DecodeWebp.cs | 2 +- .../Codecs/Webp/EncodeWebp.cs | 2 +- .../Config.HwIntrinsics.cs | 6 +- tests/ImageSharp.Benchmarks/Config.cs | 24 +- .../General/Adler32Benchmark.cs | 2 +- .../General/CopyBuffers.cs | 2 +- .../General/Crc32Benchmark.cs | 70 ---- .../General/IO/BufferedStreams.cs | 2 +- .../General/Vectorization/UInt32ToSingle.cs | 2 +- .../Vectorization/WidenBytesToUInt32.cs | 2 +- .../Processing/BokehBlur.cs | 2 +- .../ImageSharp.Benchmarks/Processing/Crop.cs | 2 +- .../Processing/DetectEdges.cs | 2 +- .../Processing/Diffuse.cs | 2 +- .../Processing/GaussianBlur.cs | 2 +- .../Processing/HistogramEqualization.cs | 2 +- .../Processing/OilPaint.cs | 2 +- .../Processing/Resize.cs | 2 +- .../Processing/Rotate.cs | 2 +- .../ImageSharp.Benchmarks/Processing/Skew.cs | 2 +- .../Formats/Png/Crc32Tests.cs | 66 ---- 54 files changed, 77 insertions(+), 581 deletions(-) delete mode 100644 src/ImageSharp/Compression/Zlib/Crc32.Lut.cs delete mode 100644 src/ImageSharp/Compression/Zlib/Crc32.cs delete mode 100644 src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf delete mode 100644 tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs delete mode 100644 tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs diff --git a/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs b/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs deleted file mode 100644 index 9145ac4a4e..0000000000 --- a/src/ImageSharp/Compression/Zlib/Crc32.Lut.cs +++ /dev/null @@ -1,69 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.Compression.Zlib; - -/// -/// Contains precalulated tables for scalar calculations. -/// -internal static partial class Crc32 -{ - /// - /// The table of all possible eight bit values for fast scalar lookup. - /// - private static readonly uint[] CrcTable = - { - 0x00000000, 0x77073096, 0xEE0E612C, 0x990951BA, 0x076DC419, - 0x706AF48F, 0xE963A535, 0x9E6495A3, 0x0EDB8832, 0x79DCB8A4, - 0xE0D5E91E, 0x97D2D988, 0x09B64C2B, 0x7EB17CBD, 0xE7B82D07, - 0x90BF1D91, 0x1DB71064, 0x6AB020F2, 0xF3B97148, 0x84BE41DE, - 0x1ADAD47D, 0x6DDDE4EB, 0xF4D4B551, 0x83D385C7, 0x136C9856, - 0x646BA8C0, 0xFD62F97A, 0x8A65C9EC, 0x14015C4F, 0x63066CD9, - 0xFA0F3D63, 0x8D080DF5, 0x3B6E20C8, 0x4C69105E, 0xD56041E4, - 0xA2677172, 0x3C03E4D1, 0x4B04D447, 0xD20D85FD, 0xA50AB56B, - 0x35B5A8FA, 0x42B2986C, 0xDBBBC9D6, 0xACBCF940, 0x32D86CE3, - 0x45DF5C75, 0xDCD60DCF, 0xABD13D59, 0x26D930AC, 0x51DE003A, - 0xC8D75180, 0xBFD06116, 0x21B4F4B5, 0x56B3C423, 0xCFBA9599, - 0xB8BDA50F, 0x2802B89E, 0x5F058808, 0xC60CD9B2, 0xB10BE924, - 0x2F6F7C87, 0x58684C11, 0xC1611DAB, 0xB6662D3D, 0x76DC4190, - 0x01DB7106, 0x98D220BC, 0xEFD5102A, 0x71B18589, 0x06B6B51F, - 0x9FBFE4A5, 0xE8B8D433, 0x7807C9A2, 0x0F00F934, 0x9609A88E, - 0xE10E9818, 0x7F6A0DBB, 0x086D3D2D, 0x91646C97, 0xE6635C01, - 0x6B6B51F4, 0x1C6C6162, 0x856530D8, 0xF262004E, 0x6C0695ED, - 0x1B01A57B, 0x8208F4C1, 0xF50FC457, 0x65B0D9C6, 0x12B7E950, - 0x8BBEB8EA, 0xFCB9887C, 0x62DD1DDF, 0x15DA2D49, 0x8CD37CF3, - 0xFBD44C65, 0x4DB26158, 0x3AB551CE, 0xA3BC0074, 0xD4BB30E2, - 0x4ADFA541, 0x3DD895D7, 0xA4D1C46D, 0xD3D6F4FB, 0x4369E96A, - 0x346ED9FC, 0xAD678846, 0xDA60B8D0, 0x44042D73, 0x33031DE5, - 0xAA0A4C5F, 0xDD0D7CC9, 0x5005713C, 0x270241AA, 0xBE0B1010, - 0xC90C2086, 0x5768B525, 0x206F85B3, 0xB966D409, 0xCE61E49F, - 0x5EDEF90E, 0x29D9C998, 0xB0D09822, 0xC7D7A8B4, 0x59B33D17, - 0x2EB40D81, 0xB7BD5C3B, 0xC0BA6CAD, 0xEDB88320, 0x9ABFB3B6, - 0x03B6E20C, 0x74B1D29A, 0xEAD54739, 0x9DD277AF, 0x04DB2615, - 0x73DC1683, 0xE3630B12, 0x94643B84, 0x0D6D6A3E, 0x7A6A5AA8, - 0xE40ECF0B, 0x9309FF9D, 0x0A00AE27, 0x7D079EB1, 0xF00F9344, - 0x8708A3D2, 0x1E01F268, 0x6906C2FE, 0xF762575D, 0x806567CB, - 0x196C3671, 0x6E6B06E7, 0xFED41B76, 0x89D32BE0, 0x10DA7A5A, - 0x67DD4ACC, 0xF9B9DF6F, 0x8EBEEFF9, 0x17B7BE43, 0x60B08ED5, - 0xD6D6A3E8, 0xA1D1937E, 0x38D8C2C4, 0x4FDFF252, 0xD1BB67F1, - 0xA6BC5767, 0x3FB506DD, 0x48B2364B, 0xD80D2BDA, 0xAF0A1B4C, - 0x36034AF6, 0x41047A60, 0xDF60EFC3, 0xA867DF55, 0x316E8EEF, - 0x4669BE79, 0xCB61B38C, 0xBC66831A, 0x256FD2A0, 0x5268E236, - 0xCC0C7795, 0xBB0B4703, 0x220216B9, 0x5505262F, 0xC5BA3BBE, - 0xB2BD0B28, 0x2BB45A92, 0x5CB36A04, 0xC2D7FFA7, 0xB5D0CF31, - 0x2CD99E8B, 0x5BDEAE1D, 0x9B64C2B0, 0xEC63F226, 0x756AA39C, - 0x026D930A, 0x9C0906A9, 0xEB0E363F, 0x72076785, 0x05005713, - 0x95BF4A82, 0xE2B87A14, 0x7BB12BAE, 0x0CB61B38, 0x92D28E9B, - 0xE5D5BE0D, 0x7CDCEFB7, 0x0BDBDF21, 0x86D3D2D4, 0xF1D4E242, - 0x68DDB3F8, 0x1FDA836E, 0x81BE16CD, 0xF6B9265B, 0x6FB077E1, - 0x18B74777, 0x88085AE6, 0xFF0F6A70, 0x66063BCA, 0x11010B5C, - 0x8F659EFF, 0xF862AE69, 0x616BFFD3, 0x166CCF45, 0xA00AE278, - 0xD70DD2EE, 0x4E048354, 0x3903B3C2, 0xA7672661, 0xD06016F7, - 0x4969474D, 0x3E6E77DB, 0xAED16A4A, 0xD9D65ADC, 0x40DF0B66, - 0x37D83BF0, 0xA9BCAE53, 0xDEBB9EC5, 0x47B2CF7F, 0x30B5FFE9, - 0xBDBDF21C, 0xCABAC28A, 0x53B39330, 0x24B4A3A6, 0xBAD03605, - 0xCDD70693, 0x54DE5729, 0x23D967BF, 0xB3667A2E, 0xC4614AB8, - 0x5D681B02, 0x2A6F2B94, 0xB40BBE37, 0xC30C8EA1, 0x5A05DF1B, - 0x2D02EF8D - }; -} diff --git a/src/ImageSharp/Compression/Zlib/Crc32.cs b/src/ImageSharp/Compression/Zlib/Crc32.cs deleted file mode 100644 index 2d0a09bd4c..0000000000 --- a/src/ImageSharp/Compression/Zlib/Crc32.cs +++ /dev/null @@ -1,308 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.X86; -using ArmCrc32 = System.Runtime.Intrinsics.Arm.Crc32; - -namespace SixLabors.ImageSharp.Compression.Zlib; - -/// -/// Calculates the 32 bit Cyclic Redundancy Check (CRC) checksum of a given buffer -/// according to the IEEE 802.3 specification. -/// -internal static partial class Crc32 -{ - /// - /// The default initial seed value of a Crc32 checksum calculation. - /// - public const uint SeedValue = 0U; - - private const int MinBufferSize = 64; - private const int ChunksizeMask = 15; - - // Definitions of the bit-reflected domain constants k1, k2, k3, etc and - // the CRC32+Barrett polynomials given at the end of the paper. - private static readonly ulong[] K05Poly = - { - 0x0154442bd4, 0x01c6e41596, // k1, k2 - 0x01751997d0, 0x00ccaa009e, // k3, k4 - 0x0163cd6124, 0x0000000000, // k5, k0 - 0x01db710641, 0x01f7011641 // polynomial - }; - - /// - /// Calculates the CRC checksum with the bytes taken from the span. - /// - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(ReadOnlySpan buffer) - => Calculate(SeedValue, buffer); - - /// - /// Calculates the CRC checksum with the bytes taken from the span and seed. - /// - /// The input CRC value. - /// The readonly span of bytes. - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static uint Calculate(uint crc, ReadOnlySpan buffer) - { - if (buffer.IsEmpty) - { - return crc; - } - - if (Sse41.IsSupported && Pclmulqdq.IsSupported && buffer.Length >= MinBufferSize) - { - return ~CalculateSse(~crc, buffer); - } - - if (ArmCrc32.Arm64.IsSupported) - { - return ~CalculateArm64(~crc, buffer); - } - - if (ArmCrc32.IsSupported) - { - return ~CalculateArm(~crc, buffer); - } - - return ~CalculateScalar(~crc, buffer); - } - - // Based on https://github.com/chromium/chromium/blob/master/third_party/zlib/crc32_simd.c - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateSse(uint crc, ReadOnlySpan buffer) - { - int chunksize = buffer.Length & ~ChunksizeMask; - int length = chunksize; - - fixed (byte* bufferPtr = buffer) - { - fixed (ulong* k05PolyPtr = K05Poly) - { - byte* localBufferPtr = bufferPtr; - ulong* localK05PolyPtr = k05PolyPtr; - - // There's at least one block of 64. - Vector128 x1 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); - Vector128 x2 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); - Vector128 x3 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); - Vector128 x4 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); - Vector128 x5; - - x1 = Sse2.Xor(x1, Sse2.ConvertScalarToVector128UInt32(crc).AsUInt64()); - - // k1, k2 - Vector128 x0 = Sse2.LoadVector128(localK05PolyPtr + 0x0); - - localBufferPtr += 64; - length -= 64; - - // Parallel fold blocks of 64, if any. - while (length >= 64) - { - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - Vector128 x6 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); - Vector128 x7 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x00); - Vector128 x8 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x00); - - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x11); - x3 = Pclmulqdq.CarrylessMultiply(x3, x0, 0x11); - x4 = Pclmulqdq.CarrylessMultiply(x4, x0, 0x11); - - Vector128 y5 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x00)); - Vector128 y6 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x10)); - Vector128 y7 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x20)); - Vector128 y8 = Sse2.LoadVector128((ulong*)(localBufferPtr + 0x30)); - - x1 = Sse2.Xor(x1, x5); - x2 = Sse2.Xor(x2, x6); - x3 = Sse2.Xor(x3, x7); - x4 = Sse2.Xor(x4, x8); - - x1 = Sse2.Xor(x1, y5); - x2 = Sse2.Xor(x2, y6); - x3 = Sse2.Xor(x3, y7); - x4 = Sse2.Xor(x4, y8); - - localBufferPtr += 64; - length -= 64; - } - - // Fold into 128-bits. - // k3, k4 - x0 = Sse2.LoadVector128(k05PolyPtr + 0x2); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x2); - x1 = Sse2.Xor(x1, x5); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x3); - x1 = Sse2.Xor(x1, x5); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x4); - x1 = Sse2.Xor(x1, x5); - - // Single fold blocks of 16, if any. - while (length >= 16) - { - x2 = Sse2.LoadVector128((ulong*)localBufferPtr); - - x5 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x11); - x1 = Sse2.Xor(x1, x2); - x1 = Sse2.Xor(x1, x5); - - localBufferPtr += 16; - length -= 16; - } - - // Fold 128 - bits to 64 - bits. - x2 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x10); - x3 = Vector128.Create(~0, 0, ~0, 0).AsUInt64(); // _mm_setr_epi32 on x86 - x1 = Sse2.ShiftRightLogical128BitLane(x1, 8); - x1 = Sse2.Xor(x1, x2); - - // k5, k0 - x0 = Sse2.LoadScalarVector128(localK05PolyPtr + 0x4); - - x2 = Sse2.ShiftRightLogical128BitLane(x1, 4); - x1 = Sse2.And(x1, x3); - x1 = Pclmulqdq.CarrylessMultiply(x1, x0, 0x00); - x1 = Sse2.Xor(x1, x2); - - // Barret reduce to 32-bits. - // polynomial - x0 = Sse2.LoadVector128(localK05PolyPtr + 0x6); - - x2 = Sse2.And(x1, x3); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x10); - x2 = Sse2.And(x2, x3); - x2 = Pclmulqdq.CarrylessMultiply(x2, x0, 0x00); - x1 = Sse2.Xor(x1, x2); - - crc = (uint)Sse41.Extract(x1.AsInt32(), 1); - return buffer.Length - chunksize == 0 ? crc : CalculateScalar(crc, buffer[chunksize..]); - } - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateArm(uint crc, ReadOnlySpan buffer) - { - fixed (byte* bufferPtr = buffer) - { - byte* localBufferPtr = bufferPtr; - int len = buffer.Length; - - while (len > 0 && ((ulong)localBufferPtr & 3) != 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - uint* intBufferPtr = (uint*)localBufferPtr; - - while (len >= 8 * sizeof(uint)) - { - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - len -= 8 * sizeof(uint); - } - - while (len >= sizeof(uint)) - { - crc = ArmCrc32.ComputeCrc32(crc, *intBufferPtr++); - len -= sizeof(uint); - } - - localBufferPtr = (byte*)intBufferPtr; - - while (len > 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - return crc; - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static unsafe uint CalculateArm64(uint crc, ReadOnlySpan buffer) - { - fixed (byte* bufferPtr = buffer) - { - byte* localBufferPtr = bufferPtr; - int len = buffer.Length; - - while (len > 0 && ((ulong)localBufferPtr & 7) != 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - ulong* longBufferPtr = (ulong*)localBufferPtr; - - while (len >= 8 * sizeof(ulong)) - { - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - len -= 8 * sizeof(ulong); - } - - while (len >= sizeof(ulong)) - { - crc = ArmCrc32.Arm64.ComputeCrc32(crc, *longBufferPtr++); - len -= sizeof(ulong); - } - - localBufferPtr = (byte*)longBufferPtr; - - while (len > 0) - { - crc = ArmCrc32.ComputeCrc32(crc, *localBufferPtr++); - len--; - } - - return crc; - } - } - - [MethodImpl(InliningOptions.HotPath | InliningOptions.ShortMethod)] - private static uint CalculateScalar(uint crc, ReadOnlySpan buffer) - { - ref uint crcTableRef = ref MemoryMarshal.GetReference(CrcTable.AsSpan()); - ref byte bufferRef = ref MemoryMarshal.GetReference(buffer); - - for (int i = 0; i < buffer.Length; i++) - { - crc = Unsafe.Add(ref crcTableRef, (crc ^ Unsafe.Add(ref bufferRef, i)) & 0xFF) ^ (crc >> 8); - } - - return crc; - } -} diff --git a/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf b/src/ImageSharp/Compression/Zlib/fast-crc-computation-generic-polynomials-pclmulqdq-paper.pdf deleted file mode 100644 index d0eca86b33851a18132d39983b2118e8da3ee7aa..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 384202 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

{LABC35aZ+t^w!fb%kfniC0^^)fHUEz8(f& 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 Cetk@ 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

  • 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 z chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); - uint validCrc = Crc32.Calculate(chunkType); - validCrc = Crc32.Calculate(validCrc, chunk.Data.GetSpan()); + Crc32 crc32 = new(); + crc32.Append(chunkType); + crc32.Append(chunk.Data.GetSpan()); - if (validCrc != inputCrc) + if (crc32.GetCurrentHashAsUInt32() != inputCrc) { string chunkTypeName = Encoding.ASCII.GetString(chunkType); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ddef1c9cd9..751df49f1d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; +using System.IO.Hashing; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; @@ -1363,16 +1364,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable stream.Write(buffer); - uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer + Crc32 crc32 = new(); + crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc = Crc32.Calculate(crc, data.Slice(offset, length)); + crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } @@ -1395,16 +1397,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable stream.Write(buffer); - uint crc = Crc32.Calculate(buffer[4..]); // Write the type buffer + Crc32 crc32 = new(); + crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc = Crc32.Calculate(crc, data.Slice(offset, length)); + crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc); + BinaryPrimitives.WriteUInt32BigEndian(buffer, crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } diff --git a/src/ImageSharp/ImageSharp.csproj b/src/ImageSharp/ImageSharp.csproj index 4c08fc017b..6096bd33e3 100644 --- a/src/ImageSharp/ImageSharp.csproj +++ b/src/ImageSharp/ImageSharp.csproj @@ -47,6 +47,10 @@ + + + + True diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs index 7e6cec2018..d70c37ccba 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs @@ -14,7 +14,7 @@ using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortCore31))] +[Config(typeof(Config.Short))] public abstract class FromVector4 where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs index fe0d2a10a7..27fab64dd2 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class FromVector4_Rgb24 : FromVector4 { } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs index 2f1064439b..934a17dc94 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class ToVector4_Bgra32 : ToVector4 { [Benchmark(Baseline = true)] diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs index 2c700a733f..d5d6e31b5d 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class ToVector4_Rgb24 : ToVector4 { [Benchmark(Baseline = true)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs index 5bd806c487..eb5b3c49d9 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Bmp/DecodeBmp.cs @@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeBmp { private byte[] bmpBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs index ab6cdf28e0..3e6cfa51b0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmp.cs @@ -9,7 +9,7 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeBmp { private Stream bmpStream; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs index 50afea5a6d..fdef1b2bfc 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Bmp/EncodeBmpMultiple.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Formats.Bmp; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeBmpMultiple : MultiImageBenchmarkBase.WithImagesPreloaded { protected override IEnumerable InputImageSubfoldersOrFiles => new[] { "Bmp/", "Jpg/baseline" }; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs index 21b193ddaf..525e9f5e5a 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/DecodeGif.cs @@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeGif { private byte[] gifBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs index 048c2aadda..c3644221e1 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGif.cs @@ -12,7 +12,7 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeGif { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs index c523b5c204..9557f616ca 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Gif/EncodeGifMultiple.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Processing.Processors.Quantization; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeGifMultiple : MultiImageBenchmarkBase.WithImagesPreloaded { [Params(InputImageCategory.AllImages)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs index 51cd02bc7a..9189bec376 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/CmykColorConversion.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class CmykColorConversion : ColorConversionBenchmark { public CmykColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs index 8bf26d721d..a1d85ef466 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/GrayscaleColorConversion.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class GrayscaleColorConversion : ColorConversionBenchmark { public GrayscaleColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs index ba09644219..5e2b6fe860 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/RgbColorConversion.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class RgbColorConversion : ColorConversionBenchmark { public RgbColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs index 87e1bf5aa9..f8621c2500 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YCbCrColorConversion.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class YCbCrColorConversion : ColorConversionBenchmark { public YCbCrColorConversion() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs index 136182936f..a414b6ed47 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/ColorConversion/YccKColorConverter.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class YccKColorConverter : ColorConversionBenchmark { public YccKColorConverter() diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs index b5a7245292..f5178390f6 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpegParseStreamOnly.cs @@ -10,7 +10,7 @@ using SDSize = System.Drawing.Size; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpegParseStreamOnly { [Params(TestImages.Jpeg.BenchmarkSuite.Lake_Small444YCbCr)] diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs index bece1de5bd..389fec88be 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_Aggregate.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; /// An expensive Jpeg benchmark, running on a wide range of input images, /// showing aggregate results. ///
  • -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpeg_Aggregate : MultiImageBenchmarkBase { protected override IEnumerable InputImageSubfoldersOrFiles diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs index 035f800a9b..08df2580db 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/DecodeJpeg_ImageSpecific.cs @@ -13,7 +13,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; /// /// Image-specific Jpeg benchmarks /// -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeJpeg_ImageSpecific { private byte[] jpegBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs index d5ad59b00a..9cc61c741d 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Jpeg/IdentifyJpeg.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs.Jpeg; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class IdentifyJpeg { private byte[] jpegBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs index 986c1431c9..57de8068f0 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodeFilteredPng.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeFilteredPng { private byte[] filter0; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs index c23fa25cca..2cf62fccf2 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/DecodePng.cs @@ -9,7 +9,7 @@ using SDSize = System.Drawing.Size; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodePng { private byte[] pngBytes; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs index 26fb0f4a41..a45e7aea9b 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodeIndexedPng.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; /// Benchmarks saving png files using different quantizers. /// System.Drawing cannot save indexed png files so we cannot compare. ///
    -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeIndexedPng { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs index 5cbe88fee6..4287914783 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Png/EncodePng.cs @@ -10,7 +10,7 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodePng { // System.Drawing needs this. diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs index 363ecf908b..2ebab5e001 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/DecodeTga.cs @@ -10,7 +10,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeTga { private string TestImageFullPath => Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, this.TestImage); diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs index 935706b41b..a7f5e35893 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tga/EncodeTga.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Codecs; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeTga { private MagickImage tgaMagick; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs index 83f5fdd213..ecb87e16c5 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/DecodeTiff.cs @@ -15,7 +15,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeTiff { private string prevImage; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs index ab3b0e95ea..d3e3944051 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Tiff/EncodeTiff.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeTiff { private Stream stream; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs index 34a4ad5931..6c71a62b50 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/DecodeWebp.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class DecodeWebp { private Configuration configuration; diff --git a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs index c5fa8d03da..5be46a2220 100644 --- a/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs +++ b/tests/ImageSharp.Benchmarks/Codecs/Webp/EncodeWebp.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.Codecs; [MarkdownExporter] [HtmlExporter] -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class EncodeWebp { private MagickImage webpMagick; diff --git a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs index 5a0c574f17..92f8917cf8 100644 --- a/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs +++ b/tests/ImageSharp.Benchmarks/Config.HwIntrinsics.cs @@ -56,7 +56,7 @@ public partial class Config { public HwIntrinsics_SSE_AVX() { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithEnvironmentVariables( new EnvironmentVariable(EnableHWIntrinsic, Off), new EnvironmentVariable(FeatureSIMD, Off)) @@ -64,14 +64,14 @@ public partial class Config if (Sse.IsSupported) { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithEnvironmentVariables(new EnvironmentVariable(EnableAVX, Off)) .WithId("2. SSE")); } if (Avx.IsSupported) { - this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core60) + this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core80) .WithId("3. AVX")); } } diff --git a/tests/ImageSharp.Benchmarks/Config.cs b/tests/ImageSharp.Benchmarks/Config.cs index d95f4a202c..06e857484d 100644 --- a/tests/ImageSharp.Benchmarks/Config.cs +++ b/tests/ImageSharp.Benchmarks/Config.cs @@ -29,25 +29,25 @@ public partial class Config : ManualConfig this.SummaryStyle = SummaryStyle.Default.WithMaxParameterColumnWidth(50); } - public class MultiFramework : Config + public class Standard : Config { - public MultiFramework() => this.AddJob( - Job.Default.WithRuntime(CoreRuntime.Core60).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); + public Standard() => this.AddJob( + Job.Default.WithRuntime(CoreRuntime.Core80).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); } - public class ShortMultiFramework : Config + public class Short : Config { - public ShortMultiFramework() => this.AddJob( - Job.Default.WithRuntime(CoreRuntime.Core60).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3).WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); - } - - public class ShortCore31 : Config - { - public ShortCore31() - => this.AddJob(Job.Default.WithRuntime(CoreRuntime.Core31).WithLaunchCount(1).WithWarmupCount(3).WithIterationCount(3)); + public Short() => this.AddJob( + Job.Default.WithRuntime(CoreRuntime.Core80) + .WithLaunchCount(1) + .WithWarmupCount(3) + .WithIterationCount(3) + .WithArguments(new Argument[] { new MsBuildArgument("/p:DebugType=portable") })); } #if OS_WINDOWS +#pragma warning disable CA1416 // Validate platform compatibility private bool IsElevated => new WindowsPrincipal(WindowsIdentity.GetCurrent()).IsInRole(WindowsBuiltInRole.Administrator); +#pragma warning restore CA1416 // Validate platform compatibility #endif } diff --git a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs index 1aac3cff50..30023feca8 100644 --- a/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs +++ b/tests/ImageSharp.Benchmarks/General/Adler32Benchmark.cs @@ -7,7 +7,7 @@ using SharpAdler32 = ICSharpCode.SharpZipLib.Checksum.Adler32; namespace SixLabors.ImageSharp.Benchmarks.General; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class Adler32Benchmark { private byte[] data; diff --git a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs index 3929f7c5ac..031f9ecf27 100644 --- a/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs +++ b/tests/ImageSharp.Benchmarks/General/CopyBuffers.cs @@ -14,7 +14,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General; /// - Span.CopyTo() has terrible performance on classic .NET Framework /// - Buffer.MemoryCopy() performance is good enough for all sizes (but needs pinning) ///
    -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class CopyBuffers { private byte[] destArray; diff --git a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs b/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs deleted file mode 100644 index fdc9e26b60..0000000000 --- a/tests/ImageSharp.Benchmarks/General/Crc32Benchmark.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using BenchmarkDotNet.Attributes; -using SixLabors.ImageSharp.Compression.Zlib; -using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; - -namespace SixLabors.ImageSharp.Benchmarks.General; - -[Config(typeof(Config.ShortMultiFramework))] -public class Crc32Benchmark -{ - private byte[] data; - private readonly SharpCrc32 crc = new SharpCrc32(); - - [Params(1024, 2048, 4096)] - public int Count { get; set; } - - [GlobalSetup] - public void SetUp() - { - this.data = new byte[this.Count]; - new Random(1).NextBytes(this.data); - } - - [Benchmark(Baseline = true)] - public long SharpZipLibCalculate() - { - this.crc.Reset(); - this.crc.Update(this.data); - return this.crc.Value; - } - - [Benchmark] - public long SixLaborsCalculate() - { - return Crc32.Calculate(this.data); - } -} - -// ########## 17/05/2020 ########## -// -// | Method | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -// |--------------------- |-------------- |------ |-------------:|-------------:|-----------:|------:|--------:|------:|------:|------:|----------:| -// | SharpZipLibCalculate | .NET 4.7.2 | 1024 | 2,797.77 ns | 278.697 ns | 15.276 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 1024 | 2,275.56 ns | 216.100 ns | 11.845 ns | 0.81 | 0.01 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 1024 | 2,923.43 ns | 2,656.882 ns | 145.633 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 1024 | 2,257.79 ns | 75.081 ns | 4.115 ns | 0.77 | 0.04 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 1024 | 2,764.14 ns | 86.281 ns | 4.729 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 1024 | 49.32 ns | 1.813 ns | 0.099 ns | 0.02 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET 4.7.2 | 2048 | 5,603.71 ns | 427.240 ns | 23.418 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 2048 | 4,525.02 ns | 33.931 ns | 1.860 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 2048 | 5,563.32 ns | 49.337 ns | 2.704 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 2048 | 4,519.61 ns | 29.837 ns | 1.635 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 2048 | 5,543.37 ns | 518.551 ns | 28.424 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 2048 | 89.07 ns | 3.312 ns | 0.182 ns | 0.02 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET 4.7.2 | 4096 | 11,396.95 ns | 373.450 ns | 20.470 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET 4.7.2 | 4096 | 9,070.35 ns | 271.083 ns | 14.859 ns | 0.80 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 2.1 | 4096 | 11,127.81 ns | 239.177 ns | 13.110 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 2.1 | 4096 | 9,050.46 ns | 230.916 ns | 12.657 ns | 0.81 | 0.00 | - | - | - | - | -// | | | | | | | | | | | | | -// | SharpZipLibCalculate | .NET Core 3.1 | 4096 | 11,098.62 ns | 687.978 ns | 37.710 ns | 1.00 | 0.00 | - | - | - | - | -// | SixLaborsCalculate | .NET Core 3.1 | 4096 | 168.11 ns | 3.633 ns | 0.199 ns | 0.02 | 0.00 | - | - | - | - | diff --git a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs index 2a926d1cd8..9560d6ee71 100644 --- a/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs +++ b/tests/ImageSharp.Benchmarks/General/IO/BufferedStreams.cs @@ -6,7 +6,7 @@ using SixLabors.ImageSharp.IO; namespace SixLabors.ImageSharp.Benchmarks.IO; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class BufferedStreams { private readonly byte[] buffer = CreateTestBytes(); diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs index fc4dc1fa16..5f1f5666de 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/UInt32ToSingle.cs @@ -7,7 +7,7 @@ using BenchmarkDotNet.Attributes; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class UInt32ToSingle { private float[] data; diff --git a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs index f391e42012..da7ddae41e 100644 --- a/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs +++ b/tests/ImageSharp.Benchmarks/General/Vectorization/WidenBytesToUInt32.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Tuples; namespace SixLabors.ImageSharp.Benchmarks.General.Vectorization; -[Config(typeof(Config.ShortMultiFramework))] +[Config(typeof(Config.Short))] public class WidenBytesToUInt32 { private byte[] source; diff --git a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs index 441500c88c..58c23d2fe7 100644 --- a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class BokehBlur { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/Crop.cs b/tests/ImageSharp.Benchmarks/Processing/Crop.cs index d802d3293a..0432b76249 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Crop.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Crop.cs @@ -11,7 +11,7 @@ using SDSize = System.Drawing.Size; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Crop { [Benchmark(Baseline = true, Description = "System.Drawing Crop")] diff --git a/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs b/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs index 9371906965..c48f3e4f49 100644 --- a/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs +++ b/tests/ImageSharp.Benchmarks/Processing/DetectEdges.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class DetectEdges { private Image image; diff --git a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs index c74c4a858a..bf760aa2d9 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Diffuse { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs index 0123f4d3b8..160df21e62 100644 --- a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Samplers; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class GaussianBlur { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs b/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs index 6292b793ec..135145a312 100644 --- a/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs +++ b/tests/ImageSharp.Benchmarks/Processing/HistogramEqualization.cs @@ -9,7 +9,7 @@ using SixLabors.ImageSharp.Tests; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class HistogramEqualization { private Image image; diff --git a/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs b/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs index 239d5a93bc..e3e413fe49 100644 --- a/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs +++ b/tests/ImageSharp.Benchmarks/Processing/OilPaint.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class OilPaint { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/Resize.cs b/tests/ImageSharp.Benchmarks/Processing/Resize.cs index ae993cd25b..05baceb6a0 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Resize.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Resize.cs @@ -12,7 +12,7 @@ using SDImage = System.Drawing.Image; namespace SixLabors.ImageSharp.Benchmarks; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public abstract class Resize where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs index b9b0f6b3df..89d2966d7c 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Rotate { [Benchmark] diff --git a/tests/ImageSharp.Benchmarks/Processing/Skew.cs b/tests/ImageSharp.Benchmarks/Processing/Skew.cs index 26f2e7d2d6..baeff29a85 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Skew.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Skew.cs @@ -7,7 +7,7 @@ using SixLabors.ImageSharp.Processing; namespace SixLabors.ImageSharp.Benchmarks.Processing; -[Config(typeof(Config.MultiFramework))] +[Config(typeof(Config.Standard))] public class Skew { [Benchmark] diff --git a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs b/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs deleted file mode 100644 index ff91590f95..0000000000 --- a/tests/ImageSharp.Tests/Formats/Png/Crc32Tests.cs +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using SixLabors.ImageSharp.Compression.Zlib; -using SixLabors.ImageSharp.Tests.TestUtilities; -using SharpCrc32 = ICSharpCode.SharpZipLib.Checksum.Crc32; - -namespace SixLabors.ImageSharp.Tests.Formats.Png; - -[Trait("Format", "Png")] -public class Crc32Tests -{ - [Theory] - [InlineData(0)] - [InlineData(1)] - [InlineData(2)] - public void CalculateCrc_ReturnsCorrectResultWhenEmpty(uint input) => Assert.Equal(input, Crc32.Calculate(input, default)); - - [Theory] - [InlineData(0)] - [InlineData(8)] - [InlineData(215)] - [InlineData(1024)] - [InlineData(1024 + 15)] - [InlineData(2034)] - [InlineData(4096)] - public void CalculateCrc_MatchesReference(int length) => CalculateCrcAndCompareToReference(length); - - private static void CalculateCrcAndCompareToReference(int length) - { - // arrange - byte[] data = GetBuffer(length); - SharpCrc32 crc = new(); - crc.Update(data); - long expected = crc.Value; - - // act - long actual = Crc32.Calculate(data); - - // assert - Assert.Equal(expected, actual); - } - - private static byte[] GetBuffer(int length) - { - byte[] data = new byte[length]; - new Random(1).NextBytes(data); - - return data; - } - - [Fact] - public void RunCalculateCrcTest_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.AllowAll); - - [Fact] - public void RunCalculateCrcTest_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunCalculateCrcTest, HwIntrinsics.DisableHWIntrinsic); - - private static void RunCalculateCrcTest() - { - int[] testData = { 0, 8, 215, 1024, 1024 + 15, 2034, 4096 }; - for (int i = 0; i < testData.Length; i++) - { - CalculateCrcAndCompareToReference(testData[i]); - } - } -} From ea49ba226ac66366bb14bacd6e759ce511c10b51 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 9 Dec 2023 19:58:02 +1000 Subject: [PATCH 095/219] Use shared instances --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 13 ++++++++---- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 21 ++++++++++++------- .../Bulk/ToVector4_Rgba32.cs | 2 +- 3 files changed, 23 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3d0ba6f97b..3eabbdef0c 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -121,6 +121,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ///
    private readonly PngCrcChunkHandling pngCrcChunkHandling; + /// + /// A reusable Crc32 hashing instance. + /// + private readonly Crc32 crc32 = new(); + /// /// Initializes a new instance of the class. /// @@ -1912,11 +1917,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals Span chunkType = stackalloc byte[4]; BinaryPrimitives.WriteUInt32BigEndian(chunkType, (uint)chunk.Type); - Crc32 crc32 = new(); - crc32.Append(chunkType); - crc32.Append(chunk.Data.GetSpan()); + this.crc32.Reset(); + this.crc32.Append(chunkType); + this.crc32.Append(chunk.Data.GetSpan()); - if (crc32.GetCurrentHashAsUInt32() != inputCrc) + if (this.crc32.GetCurrentHashAsUInt32() != inputCrc) { string chunkTypeName = Encoding.ASCII.GetString(chunkType); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 751df49f1d..e348d74679 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -124,6 +124,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable ///
    private int derivedTransparencyIndex = -1; + /// + /// A reusable Crc32 hashing instance. + /// + private readonly Crc32 crc32 = new(); + /// /// Initializes a new instance of the class. /// @@ -1364,17 +1369,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable stream.Write(buffer); - Crc32 crc32 = new(); - crc32.Append(buffer[4..]); // Write the type buffer + this.crc32.Reset(); + this.crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc32.Append(data.Slice(offset, length)); + this.crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc32.GetCurrentHashAsUInt32()); + BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } @@ -1397,17 +1402,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable stream.Write(buffer); - Crc32 crc32 = new(); - crc32.Append(buffer[4..]); // Write the type buffer + this.crc32.Reset(); + this.crc32.Append(buffer[4..]); // Write the type buffer if (data.Length > 0 && length > 0) { stream.Write(data, offset, length); - crc32.Append(data.Slice(offset, length)); + this.crc32.Append(data.Slice(offset, length)); } - BinaryPrimitives.WriteUInt32BigEndian(buffer, crc32.GetCurrentHashAsUInt32()); + BinaryPrimitives.WriteUInt32BigEndian(buffer, this.crc32.GetCurrentHashAsUInt32()); stream.Write(buffer, 0, 4); // write the crc } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs index 9abf0ed22a..1ceae84140 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs @@ -11,7 +11,7 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Bulk; -[Config(typeof(Config.ShortCore31))] +[Config(typeof(Config.Short))] public class ToVector4_Rgba32 : ToVector4 { [Benchmark] From 7ab7b226d93b3e06cd34e096f82101e8f91a15ad Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 8 Dec 2023 14:06:31 +0000 Subject: [PATCH 096/219] handle when foreground overhangs bottom of background --- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 14 +++++++++++++ .../Drawing/DrawImageTests.cs | 21 +++++++++++++++++++ .../Drawing/DrawImageTests/Issue2603.png | 3 +++ 3 files changed, 38 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 378ea20fa8..c51df8af80 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -96,6 +96,20 @@ internal class DrawImageProcessor : ImageProcessor top = 0; } + if (left + foregroundRectangle.Width > source.Width) + { + // will overhange, lets trim it down + int diff = (left + foregroundRectangle.Width) - source.Width; + foregroundRectangle.Width -= diff; + } + + if (top + foregroundRectangle.Height > source.Height) + { + // will overhange, lets trim it down + int diff = (top + foregroundRectangle.Height) - source.Height; + foregroundRectangle.Height -= diff; + } + int width = foregroundRectangle.Width; int height = foregroundRectangle.Height; if (width <= 0 || height <= 0) diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 8b0db773ab..6cd6e15e25 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -251,4 +251,25 @@ public class DrawImageTests appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); } + + [Theory] + [WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)] + public void Issue2603(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image foreground = provider.GetImage(); + using Image background = new(100, 100, new Rgba32(0, 255, 255)); + + background.Mutate(c => c.DrawImage(foreground, new Point(80, 80), new Rectangle(32, 32, 32, 32), 1F)); + + background.DebugSave( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + background.CompareToReferenceOutput( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } } diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png new file mode 100644 index 0000000000..1940dbba04 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:307ef8cea7999e615420740bb0a403a64b24f1fff5356c2ac45c1952f84c5e4c +size 508 From dd705eb0587f147f748aa0dec5032c2738f23327 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 9 Dec 2023 10:32:00 +0000 Subject: [PATCH 097/219] prevent potential overflow --- .../Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index c51df8af80..e2aca1d90a 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -96,14 +96,14 @@ internal class DrawImageProcessor : ImageProcessor top = 0; } - if (left + foregroundRectangle.Width > source.Width) + if (left > source.Width - foregroundRectangle.Width) { // will overhange, lets trim it down int diff = (left + foregroundRectangle.Width) - source.Width; foregroundRectangle.Width -= diff; } - if (top + foregroundRectangle.Height > source.Height) + if (top > source.Height - foregroundRectangle.Height) { // will overhange, lets trim it down int diff = (top + foregroundRectangle.Height) - source.Height; From 6c7b59fc06cf8da9af070cad8aebae059cb68e47 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Sat, 9 Dec 2023 10:43:21 +0000 Subject: [PATCH 098/219] reduce to a single par of clamping operations --- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 16 +++------------- 1 file changed, 3 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index e2aca1d90a..031bcbdf78 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -96,19 +96,9 @@ internal class DrawImageProcessor : ImageProcessor top = 0; } - if (left > source.Width - foregroundRectangle.Width) - { - // will overhange, lets trim it down - int diff = (left + foregroundRectangle.Width) - source.Width; - foregroundRectangle.Width -= diff; - } - - if (top > source.Height - foregroundRectangle.Height) - { - // will overhange, lets trim it down - int diff = (top + foregroundRectangle.Height) - source.Height; - foregroundRectangle.Height -= diff; - } + // clamp the height/width to the availible space left to prevent overflowing + foregroundRectangle.Width = Math.Min(source.Width - left, foregroundRectangle.Width); + foregroundRectangle.Height = Math.Min(source.Height - top, foregroundRectangle.Height); int width = foregroundRectangle.Width; int height = foregroundRectangle.Height; From 9906ee5ad7944946065004ae4d25b7baf8414ff1 Mon Sep 17 00:00:00 2001 From: Scott Williams Date: Fri, 8 Dec 2023 13:40:30 +0000 Subject: [PATCH 099/219] correctly calculate Rect when negative target set --- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 2 ++ .../Drawing/DrawImageTests.cs | 21 +++++++++++++++++++ .../DrawImageTests/Issue2608_NegOffset.png | 3 +++ 3 files changed, 26 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 378ea20fa8..2ac8365042 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -87,12 +87,14 @@ internal class DrawImageProcessor : ImageProcessor if (this.BackgroundLocation.X < 0) { foregroundRectangle.Width += this.BackgroundLocation.X; + foregroundRectangle.X -= this.BackgroundLocation.X; left = 0; } if (this.BackgroundLocation.Y < 0) { foregroundRectangle.Height += this.BackgroundLocation.Y; + foregroundRectangle.Y -= this.BackgroundLocation.Y; top = 0; } diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 8b0db773ab..4d1c592ef2 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -251,4 +251,25 @@ public class DrawImageTests appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); } + + [Theory] + [WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)] + public void Issue2608_NegOffset(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image foreground = provider.GetImage(); + using Image background = new(100, 100, new Rgba32(0, 255, 255)); + + background.Mutate(c => c.DrawImage(foreground, new Point(-10, -10), new Rectangle(32, 32, 32, 32), 1F)); + + background.DebugSave( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + background.CompareToReferenceOutput( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } } diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png new file mode 100644 index 0000000000..747bbca38a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edfd0e17aa304f5b16ad42a761c044c3d617aaee9b9e1e74674567bbcd74d532 +size 590 From d8857023be06d728cb71220e1f070a592b620c7e Mon Sep 17 00:00:00 2001 From: Scott Williams <166440+tocsoft@users.noreply.github.com> Date: Sun, 10 Dec 2023 11:30:58 +0000 Subject: [PATCH 100/219] Sync 3.1 DrawImage fixes (#2612) * Handle dedup of local palette of 256 length * handle when foreground overhangs bottom of background * prevent potential overflow * reduce to a single par of clamping operations * correctly calculate Rect when negative target set --------- Co-authored-by: James Jackson-South --- .../DrawImageProcessor{TPixelBg,TPixelFg}.cs | 6 +++ .../Drawing/DrawImageTests.cs | 42 +++++++++++++++++++ .../Drawing/DrawImageTests/Issue2603.png | 3 ++ .../DrawImageTests/Issue2608_NegOffset.png | 3 ++ 4 files changed, 54 insertions(+) create mode 100644 tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png create mode 100644 tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 378ea20fa8..0d81270b16 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -87,15 +87,21 @@ internal class DrawImageProcessor : ImageProcessor if (this.BackgroundLocation.X < 0) { foregroundRectangle.Width += this.BackgroundLocation.X; + foregroundRectangle.X -= this.BackgroundLocation.X; left = 0; } if (this.BackgroundLocation.Y < 0) { foregroundRectangle.Height += this.BackgroundLocation.Y; + foregroundRectangle.Y -= this.BackgroundLocation.Y; top = 0; } + // clamp the height/width to the availible space left to prevent overflowing + foregroundRectangle.Width = Math.Min(source.Width - left, foregroundRectangle.Width); + foregroundRectangle.Height = Math.Min(source.Height - top, foregroundRectangle.Height); + int width = foregroundRectangle.Width; int height = foregroundRectangle.Height; if (width <= 0 || height <= 0) diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 8b0db773ab..533f0c6dee 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -251,4 +251,46 @@ public class DrawImageTests appendPixelTypeToFileName: false, appendSourceFileOrDescription: false); } + + [Theory] + [WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)] + public void Issue2608_NegOffset(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image foreground = provider.GetImage(); + using Image background = new(100, 100, new Rgba32(0, 255, 255)); + + background.Mutate(c => c.DrawImage(foreground, new Point(-10, -10), new Rectangle(32, 32, 32, 32), 1F)); + + background.DebugSave( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + background.CompareToReferenceOutput( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } + + [Theory] + [WithFile(TestImages.Png.Issue2447, PixelTypes.Rgba32)] + public void Issue2603(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image foreground = provider.GetImage(); + using Image background = new(100, 100, new Rgba32(0, 255, 255)); + + background.Mutate(c => c.DrawImage(foreground, new Point(80, 80), new Rectangle(32, 32, 32, 32), 1F)); + + background.DebugSave( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + + background.CompareToReferenceOutput( + provider, + appendPixelTypeToFileName: false, + appendSourceFileOrDescription: false); + } } diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png new file mode 100644 index 0000000000..1940dbba04 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2603.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:307ef8cea7999e615420740bb0a403a64b24f1fff5356c2ac45c1952f84c5e4c +size 508 diff --git a/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png new file mode 100644 index 0000000000..747bbca38a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/Drawing/DrawImageTests/Issue2608_NegOffset.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:edfd0e17aa304f5b16ad42a761c044c3d617aaee9b9e1e74674567bbcd74d532 +size 590 From db705814df9786ed45982c38bb0f665c873afc75 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Dec 2023 16:06:03 +1000 Subject: [PATCH 101/219] Add PixelComponentPrecision --- src/ImageSharp/Color/Color.cs | 2 +- src/ImageSharp/Formats/PixelTypeInfo.cs | 28 +++-- .../CieLabPlanarTiffColor{TPixel}.cs | 8 +- .../CieLabTiffColor{TPixel}.cs | 2 +- .../CmykTiffColor{TPixel}.cs | 2 +- .../PixelFormats/PixelComponentPrecision.cs | 50 ++++++++ .../PixelFormats/PixelImplementations/A8.cs | 2 +- .../PixelImplementations/Abgr32.cs | 2 +- .../PixelImplementations/Argb32.cs | 2 +- .../PixelImplementations/Bgr24.cs | 2 +- .../PixelImplementations/Bgr565.cs | 2 +- .../PixelImplementations/Bgra32.cs | 2 +- .../PixelImplementations/Bgra4444.cs | 2 +- .../PixelImplementations/Bgra5551.cs | 2 +- .../PixelImplementations/Byte4.cs | 2 +- .../PixelImplementations/HalfSingle.cs | 2 +- .../PixelImplementations/HalfVector2.cs | 2 +- .../PixelImplementations/HalfVector4.cs | 2 +- .../PixelFormats/PixelImplementations/L16.cs | 2 +- .../PixelFormats/PixelImplementations/L8.cs | 2 +- .../PixelFormats/PixelImplementations/La16.cs | 2 +- .../PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelImplementations/NormalizedByte2.cs | 2 +- .../PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelImplementations/NormalizedShort2.cs | 2 +- .../PixelImplementations/NormalizedShort4.cs | 2 +- .../Rgba1010102.PixelOperations.cs | 2 - .../PixelFormats/PixelImplementations/Rg32.cs | 2 +- .../PixelImplementations/Rgb24.cs | 2 +- .../PixelImplementations/Rgb48.cs | 2 +- .../PixelImplementations/Rgba1010102.cs | 4 +- .../PixelImplementations/Rgba32.cs | 2 +- .../PixelImplementations/Rgba64.cs | 2 +- .../PixelImplementations/RgbaVector.cs | 2 +- .../PixelImplementations/Short2.cs | 2 +- .../PixelImplementations/Short4.cs | 2 +- .../ImageSharp.Tests/PixelFormats/A8Tests.cs | 28 +++-- .../PixelFormats/Abgr32Tests.cs | 42 ++++--- .../PixelFormats/Argb32Tests.cs | 42 ++++--- .../PixelFormats/Bgr24Tests.cs | 42 ++++--- .../PixelFormats/Bgr565Tests.cs | 60 +++++---- .../PixelFormats/Bgra32Tests.cs | 42 ++++--- .../PixelFormats/Bgra4444Tests.cs | 58 +++++---- .../PixelFormats/Bgra5551Tests.cs | 67 ++++++---- .../PixelFormats/Byte4Tests.cs | 56 +++++---- .../PixelFormats/HalfSingleTests.cs | 22 +++- .../PixelFormats/HalfVector2Tests.cs | 24 +++- .../PixelFormats/HalfVector4Tests.cs | 18 ++- .../ImageSharp.Tests/PixelFormats/L16Tests.cs | 32 +++-- .../ImageSharp.Tests/PixelFormats/L8Tests.cs | 50 +++++--- .../PixelFormats/La16Tests.cs | 50 +++++--- .../PixelFormats/La32Tests.cs | 32 +++-- .../PixelFormats/NormalizedByte2Tests.cs | 20 ++- .../PixelFormats/NormalizedByte4Tests.cs | 56 +++++---- .../PixelFormats/NormalizedShort2Tests.cs | 20 ++- .../PixelFormats/NormalizedShort4Tests.cs | 56 +++++---- .../PixelFormats/Rg32Tests.cs | 20 ++- .../PixelFormats/Rgb24Tests.cs | 36 ++++-- .../PixelFormats/Rgb48Tests.cs | 26 ++-- .../PixelFormats/Rgba1010102Tests.cs | 58 +++++---- .../PixelFormats/Rgba32Tests.cs | 96 +++++++------- .../PixelFormats/Rgba64Tests.cs | 118 ++++++++++-------- .../PixelFormats/RgbaVectorTests.cs | 59 +++++---- .../PixelFormats/Short2Tests.cs | 44 ++++--- .../PixelFormats/Short4Tests.cs | 74 ++++++----- .../PixelFormats/UnPackedPixelTests.cs | 32 ++--- tests/ImageSharp.Tests/TestFormat.cs | 2 +- .../BasicTestPatternProvider.cs | 4 +- 68 files changed, 971 insertions(+), 569 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelComponentPrecision.cs diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index cebceabe09..99458d58a1 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -107,7 +107,7 @@ public readonly partial struct Color : IEquatable public static Color FromPixel(TPixel pixel) where TPixel : unmanaged, IPixel { - // Avoid boxing in case we can convert to Rgba64 safely and efficently + // Avoid boxing in case we can convert to Rgba64 safely and efficiently if (typeof(TPixel) == typeof(Rgba64)) { return new((Rgba64)(object)pixel); diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index ba26e48ee6..0c2a4f4c86 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -4,7 +4,7 @@ using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; -// TODO: Review this class as it's used to represent 2 different things. +// TODO: Review this type as it's used to represent 2 different things. // 1.The encoded image pixel format. // 2. The pixel format of the decoded image. namespace SixLabors.ImageSharp.Formats; @@ -12,37 +12,43 @@ namespace SixLabors.ImageSharp.Formats; /// /// Contains information about the pixels that make up an images visual data. /// -public readonly struct PixelTypeInfo +/// +/// Initializes a new instance of the struct. +/// +/// Color depth, in number of bits per pixel. +public readonly struct PixelTypeInfo(int bitsPerPixel) { - /// - /// Initializes a new instance of the struct. - /// - /// Color depth, in number of bits per pixel. - public PixelTypeInfo(int bitsPerPixel) - => this.BitsPerPixel = bitsPerPixel; - /// /// Gets color depth, in number of bits per pixel. /// - public int BitsPerPixel { get; init; } + public int BitsPerPixel { get; init; } = bitsPerPixel; /// /// Gets the count of the color components /// public byte ComponentCount { get; init; } + /// + /// Gets the pixel component precision. + /// + public PixelComponentPrecision? ComponentPrecision { get; init; } + /// /// Gets the pixel alpha transparency behavior. /// means unknown, unspecified. /// public PixelAlphaRepresentation? AlphaRepresentation { get; init; } - internal static PixelTypeInfo Create(byte componentCount, PixelAlphaRepresentation pixelAlphaRepresentation) + internal static PixelTypeInfo Create( + byte componentCount, + PixelComponentPrecision componentPrecision, + PixelAlphaRepresentation pixelAlphaRepresentation) where TPixel : unmanaged, IPixel => new() { BitsPerPixel = Unsafe.SizeOf() * 8, ComponentCount = componentCount, + ComponentPrecision = componentPrecision, AlphaRepresentation = pixelAlphaRepresentation }; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs index 216d173309..eb2fe353e6 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs @@ -27,17 +27,17 @@ internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder a = data[1].GetSpan(); Span b = data[2].GetSpan(); - var color = default(TPixel); + TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { - var lab = new CieLab((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]); - var rgb = ColorSpaceConverter.ToRgb(lab); + CieLab lab = new((l[offset] & 0xFF) * 100f * Inv255, (sbyte)a[offset], (sbyte)b[offset]); + Rgb rgb = ColorSpaceConverter.ToRgb(lab); - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); + color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); pixelRow[x] = color; offset++; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs index b39a646443..f5418774b6 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabTiffColor{TPixel}.cs @@ -34,7 +34,7 @@ internal class CieLabTiffColor : TiffBaseColorDecoder CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]); Rgb rgb = ColorSpaceConverter.ToRgb(lab); - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); + color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); pixelRow[x] = color; offset += 3; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs index c87051d527..2074fb2544 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs @@ -27,7 +27,7 @@ internal class CmykTiffColor : TiffBaseColorDecoder Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255); Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk); - color.FromVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); + color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); pixelRow[x] = color; offset += 4; diff --git a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs new file mode 100644 index 0000000000..8b12986578 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Provides enumeration of the maximum precision of individual components within a pixel format. +/// +public enum PixelComponentPrecision +{ + /// + /// 8-bit signed integer. + /// + SByte, + + /// + /// 8-bit unsigned integer. + /// + Byte, + + /// + /// 16-bit signed integer. + /// + Short, + + /// + /// 16-bit unsigned integer. + /// + UShort, + + /// + /// 32-bit signed integer. + /// + Int, + + /// + /// 32-bit unsigned integer. + /// + UInt, + + /// + /// 16-bit floating point. + /// + Half, + + /// + /// 32-bit floating point. + /// + Float +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 7662495ff7..33fa62d1af 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -57,7 +57,7 @@ public partial struct A8 : IPixel, IPackedVector public static bool operator !=(A8 left, A8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 8fae07aa14..66523f0408 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -185,7 +185,7 @@ public partial struct Abgr32 : IPixel, IPackedVector public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 9f36e31b8e..d3375f65f6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -185,7 +185,7 @@ public partial struct Argb32 : IPixel, IPackedVector public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 4a6caa4ce5..9d0186c835 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -89,7 +89,7 @@ public partial struct Bgr24 : IPixel public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 564a0c53f8..6135ab3e7e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -61,7 +61,7 @@ public partial struct Bgr565 : IPixel, IPackedVector public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index afd6c395ec..7da4fad4f5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -138,7 +138,7 @@ public partial struct Bgra32 : IPixel, IPackedVector public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 81f37c5543..effc0d6e5d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -59,7 +59,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index c80af59b34..14110b1d10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -62,7 +62,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 6efbc96237..f9a36305d7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -62,7 +62,7 @@ public partial struct Byte4 : IPixel, IPackedVector public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 8d658b2401..7e1997251e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -47,7 +47,7 @@ public partial struct HalfSingle : IPixel, IPackedVector public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Half, PixelAlphaRepresentation.None); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index faec2b0695..1e3854feb7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -54,7 +54,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Half, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index e9a364ed10..2331605794 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -59,7 +59,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Half, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 63c1c63c50..fa07d650bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -49,7 +49,7 @@ public partial struct L16 : IPixel, IPackedVector public static bool operator !=(L16 left, L16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index cc834fefee..28fb7ec720 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -50,7 +50,7 @@ public partial struct L8 : IPixel, IPackedVector public static bool operator !=(L8 left, L8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 53f14d16bc..99203518af 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -73,7 +73,7 @@ public partial struct La16 : IPixel, IPackedVector public static bool operator !=(La16 left, La16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index ab542c4dc2..a8c0dcd940 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -75,7 +75,7 @@ public partial struct La32 : IPixel, IPackedVector public static bool operator !=(La32 left, La32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index bb5238985c..5db53e8539 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -62,7 +62,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.SByte, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 3bc7967953..4c850e4269 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -64,7 +64,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.SByte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 17aecfbce7..7fd299d6db 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -63,7 +63,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Short, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 6bd7c140b1..ff5cd6a987 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -65,7 +65,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Short, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs index 80c54ac2bb..8dcbb319f9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba1010102.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 3f624df4a0..9a27533414 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -59,7 +59,7 @@ public partial struct Rg32 : IPixel, IPackedVector public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index ebb0e4eac0..f4c907abf0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -108,7 +108,7 @@ public partial struct Rgb24 : IPixel public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 89f6e32db4..642883ff02 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -71,7 +71,7 @@ public partial struct Rgb48 : IPixel public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 9ed14aaad9..5f289577fe 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -8,7 +8,7 @@ using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; /// -/// Packed vector type containing unsigned normalized values ranging from 0 to 1. +/// Packed vector type containing 4 unsigned normalized values ranging from 0 to 1. /// The x, y and z components use 10 bits, and the w component uses 2 bits. /// /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. @@ -62,7 +62,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index af149e3921..f775e8ae11 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -288,7 +288,7 @@ public partial struct Rgba32 : IPixel, IPackedVector } /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index a214071742..84860d66d8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -208,7 +208,7 @@ public partial struct Rgba64 : IPixel, IPackedVector public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 12f7ff2677..064064f737 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -98,7 +98,7 @@ public partial struct RgbaVector : IPixel public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Float, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index e5bbeb37ff..8af952b180 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -66,7 +66,7 @@ public partial struct Short2 : IPixel, IPackedVector public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Short, PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index c01c4394c0..4c60887df0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -68,7 +68,7 @@ public partial struct Short4 : IPixel, IPackedVector public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Short, PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index 95574a4d6c..008bc652c2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -28,8 +30,8 @@ public class A8Tests [Fact] public void A8_Equality() { - var left = new A8(16); - var right = new A8(32); + A8 left = new(16); + A8 right = new(32); Assert.True(left == new A8(16)); Assert.True(left != right); @@ -56,7 +58,7 @@ public class A8Tests public void A8_ToScaledVector4() { // Arrange - var alpha = new A8(.5F); + A8 alpha = new(.5F); // Act Vector4 actual = alpha.ToScaledVector4(); @@ -72,10 +74,10 @@ public class A8Tests public void A8_ToVector4() { // Arrange - var alpha = new A8(.5F); + A8 alpha = new(.5F); // Act - var actual = alpha.ToVector4(); + Vector4 actual = alpha.ToVector4(); // Assert Assert.Equal(0, actual.X); @@ -87,8 +89,8 @@ public class A8Tests [Fact] public void A8_ToRgba32() { - var input = new A8(128); - var expected = new Rgba32(0, 0, 0, 128); + A8 input = new(128); + Rgba32 expected = new(0, 0, 0, 128); Rgba32 actual = default; input.ToRgba32(ref actual); @@ -99,7 +101,7 @@ public class A8Tests public void A8_FromBgra5551() { // arrange - var alpha = default(A8); + A8 alpha = default; byte expected = byte.MaxValue; // act @@ -108,4 +110,14 @@ public class A8Tests // assert Assert.Equal(expected, alpha.PackedValue); } + + [Fact] + public void A8_PixelInformation() + { + PixelTypeInfo info = A8.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(1, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index 13c84784cc..3c185383c3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,8 +17,8 @@ public class Abgr32Tests [Fact] public void AreEqual() { - var color1 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color1 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.Equal(color1, color2); } @@ -27,8 +29,8 @@ public class Abgr32Tests [Fact] public void AreNotEqual() { - var color1 = new Abgr32(0, 0, byte.MaxValue, byte.MaxValue); - var color2 = new Abgr32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Abgr32 color1 = new(0, 0, byte.MaxValue, byte.MaxValue); + Abgr32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -46,7 +48,7 @@ public class Abgr32Tests [MemberData(nameof(ColorData))] public void Constructor(byte b, byte g, byte r, byte a) { - var p = new Abgr32(r, g, b, a); + Abgr32 p = new(r, g, b, a); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -57,7 +59,7 @@ public class Abgr32Tests [Fact] public unsafe void ByteLayoutIsSequentialBgra() { - var color = new Abgr32(1, 2, 3, 4); + Abgr32 color = new(1, 2, 3, 4); byte* ptr = (byte*)&color; Assert.Equal(4, ptr[0]); @@ -70,8 +72,8 @@ public class Abgr32Tests [MemberData(nameof(ColorData))] public void Equality_WhenTrue(byte r, byte g, byte b, byte a) { - var x = new Abgr32(r, g, b, a); - var y = new Abgr32(r, g, b, a); + Abgr32 x = new(r, g, b, a); + Abgr32 y = new(r, g, b, a); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -85,8 +87,8 @@ public class Abgr32Tests [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) { - var x = new Abgr32(r1, g1, b1, a1); - var y = new Abgr32(r2, g2, b2, a2); + Abgr32 x = new(r1, g1, b1, a1); + Abgr32 y = new(r2, g2, b2, a2); Assert.False(x.Equals(y)); Assert.False(x.Equals((object)y)); @@ -95,7 +97,7 @@ public class Abgr32Tests [Fact] public void FromRgba32() { - var abgr = default(Abgr32); + Abgr32 abgr = default; abgr.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, abgr.R); @@ -104,7 +106,7 @@ public class Abgr32Tests Assert.Equal(4, abgr.A); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -113,7 +115,7 @@ public class Abgr32Tests [Fact] public void FromVector4() { - var c = default(Abgr32); + Abgr32 c = default; c.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); @@ -125,7 +127,7 @@ public class Abgr32Tests [Fact] public void ToVector4() { - var abgr = new Abgr32(1, 2, 3, 4); + Abgr32 abgr = new(1, 2, 3, 4); Assert.Equal(Vec(1, 2, 3, 4), abgr.ToVector4()); } @@ -134,7 +136,7 @@ public class Abgr32Tests public void Abgr32_FromBgra5551() { // arrange - var abgr = default(Abgr32); + Abgr32 abgr = default; uint expected = uint.MaxValue; // act @@ -143,4 +145,14 @@ public class Abgr32Tests // assert Assert.Equal(expected, abgr.PackedValue); } + + [Fact] + public void Abgr32_PixelInformation() + { + PixelTypeInfo info = Abgr32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 70012afb02..f6b818fb58 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Argb32Tests [Fact] public void AreEqual() { - var color1 = new Argb32(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Argb32(new Vector4(0.0f)); - var color3 = new Argb32(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Argb32(1.0f, 0.0f, 1.0f, 1.0f); + Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Argb32 color2 = new(new Vector4(0.0f)); + Argb32 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + Argb32 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Argb32Tests [Fact] public void AreNotEqual() { - var color1 = new Argb32(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Argb32(new Vector4(1.0f)); - var color3 = new Argb32(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Argb32(1.0f, 1.0f, 0.0f, 1.0f); + Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Argb32 color2 = new(new Vector4(1.0f)); + Argb32 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Argb32 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -45,25 +47,25 @@ public class Argb32Tests [Fact] public void ConstructorAssignsProperties() { - var color1 = new Argb32(1, .1f, .133f, .864f); + Argb32 color1 = new(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - var color2 = new Argb32(1, .1f, .133f); + Argb32 color2 = new(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - var color4 = new Argb32(new Vector3(1, .1f, .133f)); + Argb32 color4 = new(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - var color5 = new Argb32(new Vector4(1, .1f, .133f, .5f)); + Argb32 color5 = new(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -93,7 +95,7 @@ public class Argb32Tests public void Argb32_ToScaledVector4() { // arrange - var argb = new Argb32(Vector4.One); + Argb32 argb = new(Vector4.One); // act Vector4 actual = argb.ToScaledVector4(); @@ -110,7 +112,7 @@ public class Argb32Tests { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); - var pixel = default(Argb32); + Argb32 pixel = default; uint expected = 0xFFFFFFFF; // act @@ -125,7 +127,7 @@ public class Argb32Tests public void Argb32_FromBgra5551() { // arrange - var argb = default(Argb32); + Argb32 argb = default; uint expected = uint.MaxValue; // act @@ -141,4 +143,14 @@ public class Argb32Tests Assert.Equal(Vector4.Zero, new Argb32(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Argb32(Vector4.One * +1234.0f).ToVector4()); } + + [Fact] + public void Argb32_PixelInformation() + { + PixelTypeInfo info = Argb32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 730e3996d9..6861dab41c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +14,8 @@ public class Bgr24Tests [Fact] public void AreEqual() { - var color1 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); - var color2 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color1 = new(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color2 = new(byte.MaxValue, 0, byte.MaxValue); Assert.Equal(color1, color2); } @@ -21,8 +23,8 @@ public class Bgr24Tests [Fact] public void AreNotEqual() { - var color1 = new Bgr24(byte.MaxValue, 0, 0); - var color2 = new Bgr24(byte.MaxValue, 0, byte.MaxValue); + Bgr24 color1 = new(byte.MaxValue, 0, 0); + Bgr24 color2 = new(byte.MaxValue, 0, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -33,7 +35,7 @@ public class Bgr24Tests [MemberData(nameof(ColorData))] public void Constructor(byte r, byte g, byte b) { - var p = new Rgb24(r, g, b); + Rgb24 p = new(r, g, b); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -43,7 +45,7 @@ public class Bgr24Tests [Fact] public unsafe void ByteLayoutIsSequentialBgr() { - var color = new Bgr24(1, 2, 3); + Bgr24 color = new(1, 2, 3); byte* ptr = (byte*)&color; Assert.Equal(3, ptr[0]); @@ -55,8 +57,8 @@ public class Bgr24Tests [MemberData(nameof(ColorData))] public void Equals_WhenTrue(byte r, byte g, byte b) { - var x = new Bgr24(r, g, b); - var y = new Bgr24(r, g, b); + Bgr24 x = new(r, g, b); + Bgr24 y = new(r, g, b); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -69,8 +71,8 @@ public class Bgr24Tests [InlineData(1, 255, 0, 0, 255, 0)] public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) { - var a = new Bgr24(r1, g1, b1); - var b = new Bgr24(r2, g2, b2); + Bgr24 a = new(r1, g1, b1); + Bgr24 b = new(r2, g2, b2); Assert.False(a.Equals(b)); Assert.False(a.Equals((object)b)); @@ -79,7 +81,7 @@ public class Bgr24Tests [Fact] public void FromRgba32() { - var rgb = default(Bgr24); + Bgr24 rgb = default; rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); @@ -87,7 +89,7 @@ public class Bgr24Tests Assert.Equal(3, rgb.B); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -96,7 +98,7 @@ public class Bgr24Tests [Fact] public void FromVector4() { - var rgb = default(Bgr24); + Bgr24 rgb = default; rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); @@ -107,7 +109,7 @@ public class Bgr24Tests [Fact] public void ToVector4() { - var rgb = new Bgr24(1, 2, 3); + Bgr24 rgb = new(1, 2, 3); Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } @@ -116,7 +118,7 @@ public class Bgr24Tests public void Bgr24_FromBgra5551() { // arrange - var bgr = default(Bgr24); + Bgr24 bgr = default; // act bgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -126,4 +128,14 @@ public class Bgr24Tests Assert.Equal(255, bgr.G); Assert.Equal(255, bgr.B); } + + [Fact] + public void Bgr24_PixelInformation() + { + PixelTypeInfo info = Bgr24.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(3, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 8245a578f9..b68b943251 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Bgr565Tests [Fact] public void AreEqual() { - var color1 = new Bgr565(0.0f, 0.0f, 0.0f); - var color2 = new Bgr565(new Vector3(0.0f)); - var color3 = new Bgr565(new Vector3(1.0f, 0.0f, 1.0f)); - var color4 = new Bgr565(1.0f, 0.0f, 1.0f); + Bgr565 color1 = new(0.0f, 0.0f, 0.0f); + Bgr565 color2 = new(new Vector3(0.0f)); + Bgr565 color3 = new(new Vector3(1.0f, 0.0f, 1.0f)); + Bgr565 color4 = new(1.0f, 0.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Bgr565Tests [Fact] public void AreNotEqual() { - var color1 = new Bgr565(0.0f, 0.0f, 0.0f); - var color2 = new Bgr565(new Vector3(1.0f)); - var color3 = new Bgr565(new Vector3(1.0f, 0.0f, 0.0f)); - var color4 = new Bgr565(1.0f, 1.0f, 0.0f); + Bgr565 color1 = new(0.0f, 0.0f, 0.0f); + Bgr565 color2 = new(new Vector3(1.0f)); + Bgr565 color3 = new(new Vector3(1.0f, 0.0f, 0.0f)); + Bgr565 color4 = new(1.0f, 1.0f, 0.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -66,7 +68,7 @@ public class Bgr565Tests public void Bgr565_ToScaledVector4() { // arrange - var bgr = new Bgr565(Vector3.One); + Bgr565 bgr = new(Vector3.One); // act Vector4 actual = bgr.ToScaledVector4(); @@ -84,7 +86,7 @@ public class Bgr565Tests // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); int expected = 0xFFFF; - var pixel = default(Bgr565); + Bgr565 pixel = default; // act pixel.FromScaledVector4(scaled); @@ -98,7 +100,7 @@ public class Bgr565Tests public void Bgr565_FromBgra5551() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expected = ushort.MaxValue; // act @@ -112,8 +114,8 @@ public class Bgr565Tests public void Bgr565_FromArgb32() { // arrange - var bgr1 = default(Bgr565); - var bgr2 = default(Bgr565); + Bgr565 bgr1 = default; + Bgr565 bgr2 = default; ushort expected1 = ushort.MaxValue; ushort expected2 = ushort.MaxValue; @@ -130,8 +132,8 @@ public class Bgr565Tests public void Bgr565_FromRgba32() { // arrange - var bgr1 = default(Bgr565); - var bgr2 = default(Bgr565); + Bgr565 bgr1 = default; + Bgr565 bgr2 = default; ushort expected1 = ushort.MaxValue; ushort expected2 = ushort.MaxValue; @@ -148,9 +150,9 @@ public class Bgr565Tests public void Bgr565_ToRgba32() { // arrange - var bgra = new Bgr565(Vector3.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgr565 bgra = new(Vector3.One); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act bgra.ToRgba32(ref actual); @@ -162,7 +164,7 @@ public class Bgr565Tests public void Bgra565_FromRgb48() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -176,7 +178,7 @@ public class Bgr565Tests public void Bgra565_FromRgba64() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -190,7 +192,7 @@ public class Bgr565Tests public void Bgr565_FromBgr24() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expected = ushort.MaxValue; // act @@ -204,7 +206,7 @@ public class Bgr565Tests public void Bgr565_FromRgb24() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expected = ushort.MaxValue; // act @@ -218,7 +220,7 @@ public class Bgr565Tests public void Bgr565_FromGrey8() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expected = ushort.MaxValue; // act @@ -232,7 +234,7 @@ public class Bgr565Tests public void Bgr565_FromGrey16() { // arrange - var bgr = default(Bgr565); + Bgr565 bgr = default; ushort expected = ushort.MaxValue; // act @@ -248,4 +250,14 @@ public class Bgr565Tests Assert.Equal(Vector3.Zero, new Bgr565(Vector3.One * -1234F).ToVector3()); Assert.Equal(Vector3.One, new Bgr565(Vector3.One * 1234F).ToVector3()); } + + [Fact] + public void Bgr565_PixelInformation() + { + PixelTypeInfo info = Bgr565.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(3, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 04c8813d58..17d184d1a5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,8 +17,8 @@ public class Bgra32Tests [Fact] public void AreEqual() { - var color1 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var color2 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color1 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.Equal(color1, color2); } @@ -27,8 +29,8 @@ public class Bgra32Tests [Fact] public void AreNotEqual() { - var color1 = new Bgra32(0, 0, byte.MaxValue, byte.MaxValue); - var color2 = new Bgra32(byte.MaxValue, byte.MaxValue, byte.MaxValue); + Bgra32 color1 = new(0, 0, byte.MaxValue, byte.MaxValue); + Bgra32 color2 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue); Assert.NotEqual(color1, color2); } @@ -46,7 +48,7 @@ public class Bgra32Tests [MemberData(nameof(ColorData))] public void Constructor(byte b, byte g, byte r, byte a) { - var p = new Bgra32(r, g, b, a); + Bgra32 p = new(r, g, b, a); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -57,7 +59,7 @@ public class Bgra32Tests [Fact] public unsafe void ByteLayoutIsSequentialBgra() { - var color = new Bgra32(1, 2, 3, 4); + Bgra32 color = new(1, 2, 3, 4); byte* ptr = (byte*)&color; Assert.Equal(3, ptr[0]); @@ -70,8 +72,8 @@ public class Bgra32Tests [MemberData(nameof(ColorData))] public void Equality_WhenTrue(byte b, byte g, byte r, byte a) { - var x = new Bgra32(r, g, b, a); - var y = new Bgra32(r, g, b, a); + Bgra32 x = new(r, g, b, a); + Bgra32 y = new(r, g, b, a); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -85,8 +87,8 @@ public class Bgra32Tests [InlineData(1, 255, 0, 0, 0, 255, 0, 0)] public void Equality_WhenFalse(byte b1, byte g1, byte r1, byte a1, byte b2, byte g2, byte r2, byte a2) { - var x = new Bgra32(r1, g1, b1, a1); - var y = new Bgra32(r2, g2, b2, a2); + Bgra32 x = new(r1, g1, b1, a1); + Bgra32 y = new(r2, g2, b2, a2); Assert.False(x.Equals(y)); Assert.False(x.Equals((object)y)); @@ -95,7 +97,7 @@ public class Bgra32Tests [Fact] public void FromRgba32() { - var bgra = default(Bgra32); + Bgra32 bgra = default; bgra.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, bgra.R); @@ -104,7 +106,7 @@ public class Bgra32Tests Assert.Equal(4, bgra.A); } - private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new Vector4( + private static Vector4 Vec(byte r, byte g, byte b, byte a = 255) => new( r / 255f, g / 255f, b / 255f, @@ -113,7 +115,7 @@ public class Bgra32Tests [Fact] public void FromVector4() { - var c = default(Bgra32); + Bgra32 c = default; c.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); @@ -125,7 +127,7 @@ public class Bgra32Tests [Fact] public void ToVector4() { - var rgb = new Bgra32(1, 2, 3, 4); + Bgra32 rgb = new(1, 2, 3, 4); Assert.Equal(Vec(1, 2, 3, 4), rgb.ToVector4()); } @@ -134,7 +136,7 @@ public class Bgra32Tests public void Bgra32_FromBgra5551() { // arrange - var bgra = default(Bgra32); + Bgra32 bgra = default; uint expected = uint.MaxValue; // act @@ -143,4 +145,14 @@ public class Bgra32Tests // assert Assert.Equal(expected, bgra.PackedValue); } + + [Fact] + public void Bgra32_PixelInformation() + { + PixelTypeInfo info = Bgra32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 543b5814f9..648ef79d5a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Bgra4444Tests [Fact] public void AreEqual() { - var color1 = new Bgra4444(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra4444(new Vector4(0.0f)); - var color3 = new Bgra4444(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Bgra4444(1.0f, 0.0f, 1.0f, 1.0f); + Bgra4444 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra4444 color2 = new(new Vector4(0.0f)); + Bgra4444 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + Bgra4444 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Bgra4444Tests [Fact] public void AreNotEqual() { - var color1 = new Bgra4444(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra4444(new Vector4(1.0f)); - var color3 = new Bgra4444(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra4444(1.0f, 1.0f, 0.0f, 1.0f); + Bgra4444 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra4444 color2 = new(new Vector4(1.0f)); + Bgra4444 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Bgra4444 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -66,7 +68,7 @@ public class Bgra4444Tests public void Bgra4444_ToScaledVector4() { // arrange - var bgra = new Bgra4444(Vector4.One); + Bgra4444 bgra = new(Vector4.One); // act Vector4 actual = bgra.ToScaledVector4(); @@ -82,9 +84,9 @@ public class Bgra4444Tests public void Bgra4444_ToRgba32() { // arrange - var bgra = new Bgra4444(Vector4.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgra4444 bgra = new(Vector4.One); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act bgra.ToRgba32(ref actual); @@ -98,7 +100,7 @@ public class Bgra4444Tests // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); int expected = 0xFFFF; - var bgra = default(Bgra4444); + Bgra4444 bgra = default; // act bgra.FromScaledVector4(scaled); @@ -112,7 +114,7 @@ public class Bgra4444Tests public void Bgra4444_FromBgra5551() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expected = ushort.MaxValue; // act @@ -126,7 +128,7 @@ public class Bgra4444Tests public void Bgra4444_FromArgb32() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -140,8 +142,8 @@ public class Bgra4444Tests public void Bgra4444_FromRgba32() { // arrange - var bgra1 = default(Bgra4444); - var bgra2 = default(Bgra4444); + Bgra4444 bgra1 = default; + Bgra4444 bgra2 = default; ushort expectedPackedValue1 = ushort.MaxValue; ushort expectedPackedValue2 = 0xFF0F; @@ -158,7 +160,7 @@ public class Bgra4444Tests public void Bgra4444_FromRgb48() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -172,7 +174,7 @@ public class Bgra4444Tests public void Bgra4444_FromRgba64() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -186,7 +188,7 @@ public class Bgra4444Tests public void Bgra4444_FromGrey16() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -200,7 +202,7 @@ public class Bgra4444Tests public void Bgra4444_FromGrey8() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -214,7 +216,7 @@ public class Bgra4444Tests public void Bgra4444_FromBgr24() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -228,7 +230,7 @@ public class Bgra4444Tests public void Bgra4444_FromRgb24() { // arrange - var bgra = default(Bgra4444); + Bgra4444 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -244,4 +246,14 @@ public class Bgra4444Tests Assert.Equal(Vector4.Zero, new Bgra4444(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra4444(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Bgra4444_PixelInformation() + { + PixelTypeInfo info = Bgra4444.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index ec54173101..e32ec665e2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Bgra5551Tests [Fact] public void AreEqual() { - var color1 = new Bgra5551(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra5551(new Vector4(0.0f)); - var color3 = new Bgra5551(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra5551(1.0f, 0.0f, 0.0f, 1.0f); + Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra5551 color2 = new(new Vector4(0.0f)); + Bgra5551 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Bgra5551 color4 = new(1.0f, 0.0f, 0.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Bgra5551Tests [Fact] public void AreNotEqual() { - var color1 = new Bgra5551(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Bgra5551(new Vector4(1.0f)); - var color3 = new Bgra5551(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Bgra5551(1.0f, 1.0f, 0.0f, 1.0f); + Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Bgra5551 color2 = new(new Vector4(1.0f)); + Bgra5551 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Bgra5551 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -71,7 +73,7 @@ public class Bgra5551Tests public void Bgra5551_ToScaledVector4() { // arrange - var bgra = new Bgra5551(Vector4.One); + Bgra5551 bgra = new(Vector4.One); // act Vector4 actual = bgra.ToScaledVector4(); @@ -87,9 +89,9 @@ public class Bgra5551Tests public void Bgra5551_ToRgba32() { // arrange - var bgra = new Bgra5551(Vector4.One); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Bgra5551 bgra = new(Vector4.One); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act bgra.ToRgba32(ref actual); @@ -103,7 +105,7 @@ public class Bgra5551Tests // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); int expected = 0xFFFF; - var pixel = default(Bgra5551); + Bgra5551 pixel = default; // act pixel.FromScaledVector4(scaled); @@ -117,9 +119,9 @@ public class Bgra5551Tests public void Bgra5551_FromBgra5551() { // arrange - var bgra = default(Bgra5551); - var actual = default(Bgra5551); - var expected = new Bgra5551(1.0f, 0.0f, 1.0f, 1.0f); + Bgra5551 bgra = default; + Bgra5551 actual = default; + Bgra5551 expected = new(1.0f, 0.0f, 1.0f, 1.0f); // act bgra.FromBgra5551(expected); @@ -133,8 +135,8 @@ public class Bgra5551Tests public void Bgra5551_FromRgba32() { // arrange - var bgra1 = default(Bgra5551); - var bgra2 = default(Bgra5551); + Bgra5551 bgra1 = default; + Bgra5551 bgra2 = default; ushort expectedPackedValue1 = ushort.MaxValue; ushort expectedPackedValue2 = 0xFC1F; @@ -151,8 +153,8 @@ public class Bgra5551Tests public void Bgra5551_FromBgra32() { // arrange - var bgra1 = default(Bgra5551); - var bgra2 = default(Bgra5551); + Bgra5551 bgra1 = default; + Bgra5551 bgra2 = default; ushort expectedPackedValue1 = ushort.MaxValue; ushort expectedPackedValue2 = 0xFC1F; @@ -169,7 +171,7 @@ public class Bgra5551Tests public void Bgra5551_FromArgb32() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -183,7 +185,7 @@ public class Bgra5551Tests public void Bgra5551_FromRgb48() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -197,7 +199,7 @@ public class Bgra5551Tests public void Bgra5551_FromRgba64() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -211,7 +213,7 @@ public class Bgra5551Tests public void Bgra5551_FromGrey16() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -225,7 +227,7 @@ public class Bgra5551Tests public void Bgra5551_FromGrey8() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -239,7 +241,7 @@ public class Bgra5551Tests public void Bgra5551_FromBgr24() { // arrange - var bgra = default(Bgra5551); + Bgra5551 bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -253,7 +255,8 @@ public class Bgra5551Tests public void Bgra5551_FromRgb24() { // arrange - var bgra = default(Bgra5551); + Bgra5551 + bgra = default; ushort expectedPackedValue = ushort.MaxValue; // act @@ -269,4 +272,14 @@ public class Bgra5551Tests Assert.Equal(Vector4.Zero, new Bgra5551(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One, new Bgra5551(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Bgra5551_PixelInformation() + { + PixelTypeInfo info = Bgra5551.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 435f073915..ce5752fbad 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Byte4Tests [Fact] public void AreEqual() { - var color1 = new Byte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Byte4(new Vector4(0.0f)); - var color3 = new Byte4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Byte4(1.0f, 0.0f, 1.0f, 1.0f); + Byte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Byte4 color2 = new(new Vector4(0.0f)); + Byte4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + Byte4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Byte4Tests [Fact] public void AreNotEqual() { - var color1 = new Byte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Byte4(new Vector4(1.0f)); - var color3 = new Byte4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Byte4(1.0f, 1.0f, 0.0f, 1.0f); + Byte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Byte4 color2 = new(new Vector4(1.0f)); + Byte4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Byte4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -63,7 +65,7 @@ public class Byte4Tests public void Byte4_ToScaledVector4() { // arrange - var byte4 = new Byte4(Vector4.One * 255); + Byte4 byte4 = new(Vector4.One * 255); // act Vector4 actual = byte4.ToScaledVector4(); @@ -79,9 +81,9 @@ public class Byte4Tests public void Byte4_ToRgba32() { // arrange - var byte4 = new Byte4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Byte4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act byte4.ToRgba32(ref actual); @@ -94,7 +96,7 @@ public class Byte4Tests { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); - var pixel = default(Byte4); + Byte4 pixel = default; uint expected = 0xFFFFFFFF; // act @@ -109,7 +111,7 @@ public class Byte4Tests public void Byte4_FromArgb32() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -123,7 +125,7 @@ public class Byte4Tests public void Byte4_FromBgr24() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -137,7 +139,7 @@ public class Byte4Tests public void Byte4_FromGrey8() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -151,7 +153,7 @@ public class Byte4Tests public void Byte4_FromGrey16() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -165,7 +167,7 @@ public class Byte4Tests public void Byte4_FromRgb24() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -179,7 +181,7 @@ public class Byte4Tests public void Byte4_FromBgra5551() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expected = 0xFFFFFFFF; // act @@ -193,7 +195,7 @@ public class Byte4Tests public void Byte4_FromRgba32() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue1 = uint.MaxValue; // act @@ -207,7 +209,7 @@ public class Byte4Tests public void Byte4_FromRgb48() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -221,7 +223,7 @@ public class Byte4Tests public void Byte4_FromRgba64() { // arrange - var byte4 = default(Byte4); + Byte4 byte4 = default; uint expectedPackedValue = uint.MaxValue; // act @@ -237,4 +239,14 @@ public class Byte4Tests Assert.Equal(Vector4.Zero, new Byte4(Vector4.One * -1234.0f).ToVector4()); Assert.Equal(Vector4.One * 255, new Byte4(Vector4.One * 1234.0f).ToVector4()); } + + [Fact] + public void Byte4_PixelInformation() + { + PixelTypeInfo info = Byte4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 9ffaf3e21c..cbff2b85e9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -25,11 +27,11 @@ public class HalfSingleTests public void HalfSingle_ToVector4() { // arrange - var halfSingle = new HalfSingle(0.5f); - var expected = new Vector4(0.5f, 0, 0, 1); + HalfSingle halfSingle = new(0.5f); + Vector4 expected = new(0.5f, 0, 0, 1); // act - var actual = halfSingle.ToVector4(); + Vector4 actual = halfSingle.ToVector4(); // assert Assert.Equal(expected, actual); @@ -39,7 +41,7 @@ public class HalfSingleTests public void HalfSingle_ToScaledVector4() { // arrange - var halfSingle = new HalfSingle(-1F); + HalfSingle halfSingle = new(-1F); // act Vector4 actual = halfSingle.ToScaledVector4(); @@ -57,7 +59,7 @@ public class HalfSingleTests // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); int expected = 48128; - var halfSingle = default(HalfSingle); + HalfSingle halfSingle = default; // act halfSingle.FromScaledVector4(scaled); @@ -66,4 +68,14 @@ public class HalfSingleTests // assert Assert.Equal(expected, actual); } + + [Fact] + public void HalfSingle_PixelInformation() + { + PixelTypeInfo info = HalfSingle.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(1, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index eda9315363..98a5cb0bff 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -30,7 +32,7 @@ public class HalfVector2Tests public void HalfVector2_ToScaledVector4() { // arrange - var halfVector = new HalfVector2(Vector2.One); + HalfVector2 halfVector = new(Vector2.One); // act Vector4 actual = halfVector.ToScaledVector4(); @@ -48,7 +50,7 @@ public class HalfVector2Tests // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); uint expected = 1006648320u; - var halfVector = default(HalfVector2); + HalfVector2 halfVector = default; // act halfVector.FromScaledVector4(scaled); @@ -62,11 +64,11 @@ public class HalfVector2Tests public void HalfVector2_ToVector4() { // arrange - var halfVector = new HalfVector2(.5F, .25F); - var expected = new Vector4(0.5f, .25F, 0, 1); + HalfVector2 halfVector = new(.5F, .25F); + Vector4 expected = new(0.5f, .25F, 0, 1); // act - var actual = halfVector.ToVector4(); + Vector4 actual = halfVector.ToVector4(); // assert Assert.Equal(expected, actual); @@ -76,7 +78,7 @@ public class HalfVector2Tests public void HalfVector2_FromBgra5551() { // arrange - var halfVector2 = default(HalfVector2); + HalfVector2 halfVector2 = default; // act halfVector2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -88,4 +90,14 @@ public class HalfVector2Tests Assert.Equal(0, actual.Z); Assert.Equal(1, actual.W); } + + [Fact] + public void HalfVector2_PixelInformation() + { + PixelTypeInfo info = HalfVector2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 77120192bb..48d10f1c1e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -38,7 +40,7 @@ public class HalfVector4Tests public void HalfVector4_ToScaledVector4() { // arrange - var halfVector4 = new HalfVector4(-Vector4.One); + HalfVector4 halfVector4 = new(-Vector4.One); // act Vector4 actual = halfVector4.ToScaledVector4(); @@ -54,7 +56,7 @@ public class HalfVector4Tests public void HalfVector4_FromScaledVector4() { // arrange - var halfVector4 = default(HalfVector4); + HalfVector4 halfVector4 = default; Vector4 scaled = new HalfVector4(-Vector4.One).ToScaledVector4(); ulong expected = 13547034390470638592uL; @@ -70,7 +72,7 @@ public class HalfVector4Tests public void HalfVector4_FromBgra5551() { // arrange - var halfVector4 = default(HalfVector4); + HalfVector4 halfVector4 = default; Vector4 expected = Vector4.One; // act @@ -79,4 +81,14 @@ public class HalfVector4Tests // assert Assert.Equal(expected, halfVector4.ToScaledVector4()); } + + [Fact] + public void HalfVector4_PixelInformation() + { + PixelTypeInfo info = HalfVector4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 685da2ddf8..18481712a0 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +14,8 @@ public class L16Tests [Fact] public void AreEqual() { - var color1 = new L16(3000); - var color2 = new L16(3000); + L16 color1 = new(3000); + L16 color2 = new(3000); Assert.Equal(color1, color2); } @@ -21,8 +23,8 @@ public class L16Tests [Fact] public void AreNotEqual() { - var color1 = new L16(12345); - var color2 = new L16(54321); + L16 color1 = new(12345); + L16 color2 = new(54321); Assert.NotEqual(color1, color2); } @@ -58,7 +60,7 @@ public class L16Tests public void L16_ToScaledVector4(ushort input) { // Arrange - var gray = new L16(input); + L16 gray = new(input); // Act Vector4 actual = gray.ToScaledVector4(); @@ -77,7 +79,7 @@ public class L16Tests // Arrange L16 gray = default; const ushort expected = 32767; - var vector = new L16(expected).ToVector4(); + Vector4 vector = new L16(expected).ToVector4(); // Act gray.FromVector4(vector); @@ -94,10 +96,10 @@ public class L16Tests public void L16_ToVector4(ushort input) { // Arrange - var gray = new L16(input); + L16 gray = new(input); // Act - var actual = gray.ToVector4(); + Vector4 actual = gray.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -132,7 +134,7 @@ public class L16Tests { // Arrange ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); - var gray = new L16(input); + L16 gray = new(input); // Act Rgba32 actual = default; @@ -149,7 +151,7 @@ public class L16Tests public void L16_FromBgra5551() { // arrange - var gray = default(L16); + L16 gray = default; ushort expected = ushort.MaxValue; // act @@ -158,4 +160,14 @@ public class L16Tests // assert Assert.Equal(expected, gray.PackedValue); } + + [Fact] + public void L16_PixelInformation() + { + PixelTypeInfo info = L16.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(1, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index afdc039a28..80dc36fa39 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -24,8 +26,8 @@ public class L8Tests [Fact] public void AreEqual() { - var color1 = new L8(100); - var color2 = new L8(100); + L8 color1 = new(100); + L8 color2 = new(100); Assert.Equal(color1, color2); } @@ -33,8 +35,8 @@ public class L8Tests [Fact] public void AreNotEqual() { - var color1 = new L8(100); - var color2 = new L8(200); + L8 color1 = new(100); + L8 color2 = new(200); Assert.NotEqual(color1, color2); } @@ -60,7 +62,7 @@ public class L8Tests public void L8_ToScaledVector4(byte input) { // Arrange - var gray = new L8(input); + L8 gray = new(input); // Act Vector4 actual = gray.ToScaledVector4(); @@ -79,7 +81,7 @@ public class L8Tests { // Arrange L8 gray = default; - var vector = new L8(luminance).ToVector4(); + Vector4 vector = new L8(luminance).ToVector4(); // Act gray.FromVector4(vector); @@ -94,10 +96,10 @@ public class L8Tests public void L8_ToVector4(byte input) { // Arrange - var gray = new L8(input); + L8 gray = new(input); // Act - var actual = gray.ToVector4(); + Vector4 actual = gray.ToVector4(); // Assert float scaledInput = input / 255F; @@ -128,7 +130,7 @@ public class L8Tests public void L8_ToRgba32(byte luminance) { // Arrange - var gray = new L8(luminance); + L8 gray = new(luminance); // Act Rgba32 actual = default; @@ -145,7 +147,7 @@ public class L8Tests public void L8_FromBgra5551() { // arrange - var grey = default(L8); + L8 grey = default; byte expected = byte.MaxValue; // act @@ -164,7 +166,7 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void L8_FromRgba32_IsInverseOf_ToRgba32(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -179,7 +181,7 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void Rgba32_ToL8_IsInverseOf_L8_ToRgba32(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -194,13 +196,13 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void ToVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); - var l8Vector = original.ToVector4(); - var rgbaVector = original.ToVector4(); + Vector4 l8Vector = original.ToVector4(); + Vector4 rgbaVector = original.ToVector4(); Assert.Equal(l8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -209,12 +211,12 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void FromVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); - var rgbaVector = original.ToVector4(); + Vector4 rgbaVector = original.ToVector4(); L8 mirror = default; mirror.FromVector4(rgbaVector); @@ -226,7 +228,7 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void ToScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -241,7 +243,7 @@ public class L8Tests [MemberData(nameof(LuminanceData))] public void FromScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new L8(luminance); + L8 original = new(luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -253,5 +255,15 @@ public class L8Tests Assert.Equal(original, mirror); } + + [Fact] + public void L8_PixelInformation() + { + PixelTypeInfo info = L8.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(1, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 92b4a4e1a1..c3d8a873ac 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -24,8 +26,8 @@ public class La16Tests [Fact] public void AreEqual() { - var color1 = new La16(100, 50); - var color2 = new La16(100, 50); + La16 color1 = new(100, 50); + La16 color2 = new(100, 50); Assert.Equal(color1, color2); } @@ -33,8 +35,8 @@ public class La16Tests [Fact] public void AreNotEqual() { - var color1 = new La16(100, 50); - var color2 = new La16(200, 50); + La16 color1 = new(100, 50); + La16 color2 = new(200, 50); Assert.NotEqual(color1, color2); } @@ -60,7 +62,7 @@ public class La16Tests public void La16_ToScaledVector4(byte input) { // Arrange - var gray = new La16(input, input); + La16 gray = new(input, input); // Act Vector4 actual = gray.ToScaledVector4(); @@ -79,7 +81,7 @@ public class La16Tests { // Arrange La16 gray = default; - var vector = new La16(luminance, luminance).ToVector4(); + Vector4 vector = new La16(luminance, luminance).ToVector4(); // Act gray.FromVector4(vector); @@ -96,10 +98,10 @@ public class La16Tests public void La16_ToVector4(byte input) { // Arrange - var gray = new La16(input, input); + La16 gray = new(input, input); // Act - var actual = gray.ToVector4(); + Vector4 actual = gray.ToVector4(); // Assert float scaledInput = input / 255F; @@ -131,7 +133,7 @@ public class La16Tests public void La16_ToRgba32(byte luminance) { // Arrange - var gray = new La16(luminance, luminance); + La16 gray = new(luminance, luminance); // Act Rgba32 actual = default; @@ -148,7 +150,7 @@ public class La16Tests public void La16_FromBgra5551() { // arrange - var grey = default(La16); + La16 grey = default; byte expected = byte.MaxValue; // act @@ -168,7 +170,7 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void La16_FromRgba32_IsInverseOf_ToRgba32(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -183,7 +185,7 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void Rgba32_ToLa16_IsInverseOf_La16_ToRgba32(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -198,13 +200,13 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void ToVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); - var la16Vector = original.ToVector4(); - var rgbaVector = original.ToVector4(); + Vector4 la16Vector = original.ToVector4(); + Vector4 rgbaVector = original.ToVector4(); Assert.Equal(la16Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -213,12 +215,12 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void FromVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); - var rgbaVector = original.ToVector4(); + Vector4 rgbaVector = original.ToVector4(); La16 mirror = default; mirror.FromVector4(rgbaVector); @@ -230,7 +232,7 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void ToScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -245,7 +247,7 @@ public class La16Tests [MemberData(nameof(LuminanceData))] public void FromScaledVector4_IsRgba32Compatible(byte luminance) { - var original = new La16(luminance, luminance); + La16 original = new(luminance, luminance); Rgba32 rgba = default; original.ToRgba32(ref rgba); @@ -257,5 +259,15 @@ public class La16Tests Assert.Equal(original, mirror); } + + [Fact] + public void La16_PixelInformation() + { + PixelTypeInfo info = La16.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index d333818c78..17e10e15d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +14,8 @@ public class La32Tests [Fact] public void AreEqual() { - var color1 = new La32(3000, 100); - var color2 = new La32(3000, 100); + La32 color1 = new(3000, 100); + La32 color2 = new(3000, 100); Assert.Equal(color1, color2); } @@ -21,8 +23,8 @@ public class La32Tests [Fact] public void AreNotEqual() { - var color1 = new La32(12345, 100); - var color2 = new La32(54321, 100); + La32 color1 = new(12345, 100); + La32 color2 = new(54321, 100); Assert.NotEqual(color1, color2); } @@ -60,7 +62,7 @@ public class La32Tests public void La32_ToScaledVector4(ushort input) { // Arrange - var gray = new La32(input, input); + La32 gray = new(input, input); // Act Vector4 actual = gray.ToScaledVector4(); @@ -79,7 +81,7 @@ public class La32Tests // Arrange La32 gray = default; const ushort expected = 32767; - var vector = new La32(expected, expected).ToVector4(); + Vector4 vector = new La32(expected, expected).ToVector4(); // Act gray.FromVector4(vector); @@ -98,10 +100,10 @@ public class La32Tests public void La32_ToVector4(ushort input) { // Arrange - var gray = new La32(input, input); + La32 gray = new(input, input); // Act - var actual = gray.ToVector4(); + Vector4 actual = gray.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -137,7 +139,7 @@ public class La32Tests { // Arrange ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); - var gray = new La32(input, ushort.MaxValue); + La32 gray = new(input, ushort.MaxValue); // Act Rgba32 actual = default; @@ -154,7 +156,7 @@ public class La32Tests public void La32_FromBgra5551() { // arrange - var gray = default(La32); + La32 gray = default; ushort expected = ushort.MaxValue; // act @@ -164,4 +166,14 @@ public class La32Tests Assert.Equal(expected, gray.L); Assert.Equal(expected, gray.A); } + + [Fact] + public void La32_PixelInformation() + { + PixelTypeInfo info = La32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 14c590d0b5..a09454f5bc 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -39,7 +41,7 @@ public class NormalizedByte2Tests public void NormalizedByte2_ToScaledVector4() { // arrange - var byte2 = new NormalizedByte2(-Vector2.One); + NormalizedByte2 byte2 = new(-Vector2.One); // act Vector4 actual = byte2.ToScaledVector4(); @@ -56,7 +58,7 @@ public class NormalizedByte2Tests { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); - var byte2 = default(NormalizedByte2); + NormalizedByte2 byte2 = default; uint expected = 0x8181; // act @@ -71,8 +73,8 @@ public class NormalizedByte2Tests public void NormalizedByte2_FromBgra5551() { // arrange - var normalizedByte2 = default(NormalizedByte2); - var expected = new Vector4(1, 1, 0, 1); + NormalizedByte2 normalizedByte2 = default; + Vector4 expected = new(1, 1, 0, 1); // act normalizedByte2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -80,4 +82,14 @@ public class NormalizedByte2Tests // assert Assert.Equal(expected, normalizedByte2.ToVector4()); } + + [Fact] + public void NormalizedByte2_PixelInformation() + { + PixelTypeInfo info = NormalizedByte2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.SByte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index ca73a6c1f4..aa0136b37d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class NormalizedByte4Tests [Fact] public void AreEqual() { - var color1 = new NormalizedByte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedByte4(new Vector4(0.0f)); - var color3 = new NormalizedByte4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new NormalizedByte4(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedByte4 color2 = new(new Vector4(0.0f)); + NormalizedByte4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + NormalizedByte4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class NormalizedByte4Tests [Fact] public void AreNotEqual() { - var color1 = new NormalizedByte4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedByte4(new Vector4(1.0f)); - var color3 = new NormalizedByte4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new NormalizedByte4(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedByte4 color2 = new(new Vector4(1.0f)); + NormalizedByte4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + NormalizedByte4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -63,7 +65,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_ToScaledVector4() { // arrange - var short4 = new NormalizedByte4(-Vector4.One); + NormalizedByte4 short4 = new(-Vector4.One); // act Vector4 actual = short4.ToScaledVector4(); @@ -79,7 +81,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromScaledVector4() { // arrange - var pixel = default(NormalizedByte4); + NormalizedByte4 pixel = default; Vector4 scaled = new NormalizedByte4(-Vector4.One).ToScaledVector4(); uint expected = 0x81818181; @@ -95,7 +97,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromArgb32() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -109,7 +111,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromBgr24() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -123,7 +125,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromGrey8() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -137,7 +139,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromGrey16() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -151,7 +153,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromRgb24() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -165,7 +167,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromRgba32() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -179,7 +181,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromBgra5551() { // arrange - var normalizedByte4 = default(NormalizedByte4); + NormalizedByte4 normalizedByte4 = default; Vector4 expected = Vector4.One; // act @@ -193,7 +195,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromRgb48() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -207,7 +209,7 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromRgba64() { // arrange - var byte4 = default(NormalizedByte4); + NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -221,13 +223,23 @@ public class NormalizedByte4Tests public void NormalizedByte4_ToRgba32() { // arrange - var byte4 = new NormalizedByte4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + NormalizedByte4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act byte4.ToRgba32(ref actual); Assert.Equal(expected, actual); } + + [Fact] + public void NormalizedByte4_PixelInformation() + { + PixelTypeInfo info = NormalizedByte4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.SByte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 70bfa1be71..6ac18fa089 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -43,7 +45,7 @@ public class NormalizedShort2Tests public void NormalizedShort2_ToScaledVector4() { // arrange - var short2 = new NormalizedShort2(-Vector2.One); + NormalizedShort2 short2 = new(-Vector2.One); // act Vector4 actual = short2.ToScaledVector4(); @@ -60,7 +62,7 @@ public class NormalizedShort2Tests { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); - var short2 = default(NormalizedShort2); + NormalizedShort2 short2 = default; uint expected = 0x80018001; // act @@ -75,8 +77,8 @@ public class NormalizedShort2Tests public void NormalizedShort2_FromBgra5551() { // arrange - var normalizedShort2 = default(NormalizedShort2); - var expected = new Vector4(1, 1, 0, 1); + NormalizedShort2 normalizedShort2 = default; + Vector4 expected = new(1, 1, 0, 1); // act normalizedShort2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -84,4 +86,14 @@ public class NormalizedShort2Tests // assert Assert.Equal(expected, normalizedShort2.ToVector4()); } + + [Fact] + public void NormalizedShort2_PixelInformation() + { + PixelTypeInfo info = NormalizedShort2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 997c6df82b..fcab7318b6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class NormalizedShort4Tests [Fact] public void AreEqual() { - var color1 = new NormalizedShort4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedShort4(new Vector4(0.0f)); - var color3 = new NormalizedShort4(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new NormalizedShort4(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedShort4 color2 = new(new Vector4(0.0f)); + NormalizedShort4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + NormalizedShort4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class NormalizedShort4Tests [Fact] public void AreNotEqual() { - var color1 = new NormalizedShort4(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new NormalizedShort4(new Vector4(1.0f)); - var color3 = new NormalizedShort4(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new NormalizedShort4(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + NormalizedShort4 color2 = new(new Vector4(1.0f)); + NormalizedShort4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + NormalizedShort4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -64,7 +66,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_ToScaledVector4() { // arrange - var short4 = new NormalizedShort4(Vector4.One); + NormalizedShort4 short4 = new(Vector4.One); // act Vector4 actual = short4.ToScaledVector4(); @@ -80,7 +82,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromScaledVector4() { // arrange - var pixel = default(NormalizedShort4); + NormalizedShort4 pixel = default; Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); ulong expected = 0x7FFF7FFF7FFF7FFF; @@ -96,7 +98,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromArgb32() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -110,7 +112,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromBgr24() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -124,7 +126,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromGrey8() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -138,7 +140,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromGrey16() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -152,7 +154,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromRgb24() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -166,7 +168,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromRgba32() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -180,7 +182,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromRgb48() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -194,7 +196,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromRgba64() { // arrange - var byte4 = default(NormalizedShort4); + NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act @@ -208,9 +210,9 @@ public class NormalizedShort4Tests public void NormalizedShort4_ToRgba32() { // arrange - var byte4 = new NormalizedShort4(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); - var expected = new Rgba32(Vector4.One); - var actual = default(Rgba32); + NormalizedShort4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Rgba32 expected = new(Vector4.One); + Rgba32 actual = default; // act byte4.ToRgba32(ref actual); @@ -222,7 +224,7 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromBgra5551() { // arrange - var normalizedShort4 = default(NormalizedShort4); + NormalizedShort4 normalizedShort4 = default; Vector4 expected = Vector4.One; // act @@ -231,4 +233,14 @@ public class NormalizedShort4Tests // assert Assert.Equal(expected, normalizedShort4.ToVector4()); } + + [Fact] + public void NormalizedShort4_PixelInformation() + { + PixelTypeInfo info = NormalizedShort4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 2900b0d292..c5c534655a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using SixLabors.ImageSharp.Formats; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -33,7 +35,7 @@ public class Rg32Tests public void Rg32_ToScaledVector4() { // arrange - var rg32 = new Rg32(Vector2.One); + Rg32 rg32 = new(Vector2.One); // act Vector4 actual = rg32.ToScaledVector4(); @@ -49,8 +51,8 @@ public class Rg32Tests public void Rg32_FromScaledVector4() { // arrange - var rg32 = new Rg32(Vector2.One); - var pixel = default(Rg32); + Rg32 rg32 = new(Vector2.One); + Rg32 pixel = default; uint expected = 0xFFFFFFFF; // act @@ -66,7 +68,7 @@ public class Rg32Tests public void Rg32_FromBgra5551() { // arrange - var rg32 = new Rg32(Vector2.One); + Rg32 rg32 = new(Vector2.One); uint expected = 0xFFFFFFFF; // act @@ -82,4 +84,14 @@ public class Rg32Tests Assert.Equal(Vector2.Zero, new Rg32(Vector2.One * -1234.0f).ToVector2()); Assert.Equal(Vector2.One, new Rg32(Vector2.One * 1234.0f).ToVector2()); } + + [Fact] + public void Rg32_PixelInformation() + { + PixelTypeInfo info = Rg32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 2d1be8ab44..dbb2e8f03d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -21,7 +23,7 @@ public class Rgb24Tests [MemberData(nameof(ColorData))] public void Constructor(byte r, byte g, byte b) { - var p = new Rgb24(r, g, b); + Rgb24 p = new(r, g, b); Assert.Equal(r, p.R); Assert.Equal(g, p.G); @@ -31,7 +33,7 @@ public class Rgb24Tests [Fact] public unsafe void ByteLayoutIsSequentialRgb() { - var color = new Rgb24(1, 2, 3); + Rgb24 color = new(1, 2, 3); byte* ptr = (byte*)&color; Assert.Equal(1, ptr[0]); @@ -43,8 +45,8 @@ public class Rgb24Tests [MemberData(nameof(ColorData))] public void Equals_WhenTrue(byte r, byte g, byte b) { - var x = new Rgb24(r, g, b); - var y = new Rgb24(r, g, b); + Rgb24 x = new(r, g, b); + Rgb24 y = new(r, g, b); Assert.True(x.Equals(y)); Assert.True(x.Equals((object)y)); @@ -57,8 +59,8 @@ public class Rgb24Tests [InlineData(1, 255, 0, 0, 255, 0)] public void Equals_WhenFalse(byte r1, byte g1, byte b1, byte r2, byte g2, byte b2) { - var a = new Rgb24(r1, g1, b1); - var b = new Rgb24(r2, g2, b2); + Rgb24 a = new(r1, g1, b1); + Rgb24 b = new(r2, g2, b2); Assert.False(a.Equals(b)); Assert.False(a.Equals((object)b)); @@ -67,7 +69,7 @@ public class Rgb24Tests [Fact] public void FromRgba32() { - var rgb = default(Rgb24); + Rgb24 rgb = default; rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); @@ -84,7 +86,7 @@ public class Rgb24Tests [Fact] public void FromVector4() { - var rgb = default(Rgb24); + Rgb24 rgb = default; rgb.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); @@ -95,7 +97,7 @@ public class Rgb24Tests [Fact] public void ToVector4() { - var rgb = new Rgb24(1, 2, 3); + Rgb24 rgb = new(1, 2, 3); Assert.Equal(Vec(1, 2, 3), rgb.ToVector4()); } @@ -104,9 +106,9 @@ public class Rgb24Tests public void ToRgba32() { // arrange - var rgb = new Rgb24(1, 2, 3); + Rgb24 rgb = new(1, 2, 3); Rgba32 rgba = default; - var expected = new Rgba32(1, 2, 3, 255); + Rgba32 expected = new(1, 2, 3, 255); // act rgb.ToRgba32(ref rgba); @@ -119,7 +121,7 @@ public class Rgb24Tests public void Rgb24_FromBgra5551() { // arrange - var rgb = new Rgb24(255, 255, 255); + Rgb24 rgb = new(255, 255, 255); // act rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -129,4 +131,14 @@ public class Rgb24Tests Assert.Equal(255, rgb.G); Assert.Equal(255, rgb.B); } + + [Fact] + public void Rgb24_PixelInformation() + { + PixelTypeInfo info = Rgb24.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(3, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index d8a61940b2..04bbaf7f78 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,7 +14,7 @@ public class Rgb48Tests [Fact] public void Rgb48_Values() { - var rgb = new Rgba64(5243, 9830, 19660, 29491); + Rgba64 rgb = new(5243, 9830, 19660, 29491); Assert.Equal(5243, rgb.R); Assert.Equal(9830, rgb.G); @@ -32,9 +34,9 @@ public class Rgb48Tests public void Rgb48_FromScaledVector4() { // arrange - var pixel = default(Rgb48); - var short3 = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); - var expected = new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + Rgb48 pixel = default; + Rgb48 short3 = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); + Rgb48 expected = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 scaled = short3.ToScaledVector4(); @@ -48,8 +50,8 @@ public class Rgb48Tests public void Rgb48_ToRgba32() { // arrange - var rgba48 = new Rgb48(5140, 9766, 19532); - var expected = new Rgba32(20, 38, 76, 255); + Rgb48 rgba48 = new(5140, 9766, 19532); + Rgba32 expected = new(20, 38, 76, 255); // act Rgba32 actual = default; @@ -63,7 +65,7 @@ public class Rgb48Tests public void Rgb48_FromBgra5551() { // arrange - var rgb = default(Rgb48); + Rgb48 rgb = default; ushort expected = ushort.MaxValue; // act @@ -74,4 +76,14 @@ public class Rgb48Tests Assert.Equal(expected, rgb.G); Assert.Equal(expected, rgb.B); } + + [Fact] + public void Rgb48_PixelInformation() + { + PixelTypeInfo info = Rgb48.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(3, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 0c28b35c69..678ac2274e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -15,10 +17,10 @@ public class Rgba1010102Tests [Fact] public void AreEqual() { - var color1 = new Rgba1010102(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Rgba1010102(new Vector4(0.0f)); - var color3 = new Rgba1010102(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - var color4 = new Rgba1010102(1.0f, 0.0f, 1.0f, 1.0f); + Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Rgba1010102 color2 = new(new Vector4(0.0f)); + Rgba1010102 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); + Rgba1010102 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -30,10 +32,10 @@ public class Rgba1010102Tests [Fact] public void AreNotEqual() { - var color1 = new Rgba1010102(0.0f, 0.0f, 0.0f, 0.0f); - var color2 = new Rgba1010102(new Vector4(1.0f)); - var color3 = new Rgba1010102(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - var color4 = new Rgba1010102(1.0f, 1.0f, 0.0f, 1.0f); + Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); + Rgba1010102 color2 = new(new Vector4(1.0f)); + Rgba1010102 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); + Rgba1010102 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -66,7 +68,7 @@ public class Rgba1010102Tests public void Rgba1010102_ToScaledVector4() { // arrange - var rgba = new Rgba1010102(Vector4.One); + Rgba1010102 rgba = new(Vector4.One); // act Vector4 actual = rgba.ToScaledVector4(); @@ -82,8 +84,8 @@ public class Rgba1010102Tests public void Rgba1010102_FromScaledVector4() { // arrange - var rgba = new Rgba1010102(Vector4.One); - var actual = default(Rgba1010102); + Rgba1010102 rgba = new(Vector4.One); + Rgba1010102 actual = default; uint expected = 0xFFFFFFFF; // act @@ -98,7 +100,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromBgra5551() { // arrange - var rgba = new Rgba1010102(Vector4.One); + Rgba1010102 rgba = new(Vector4.One); uint expected = 0xFFFFFFFF; // act @@ -112,7 +114,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromArgb32() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -126,8 +128,8 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgba32() { // arrange - var rgba1 = default(Rgba1010102); - var rgba2 = default(Rgba1010102); + Rgba1010102 rgba1 = default; + Rgba1010102 rgba2 = default; uint expectedPackedValue1 = uint.MaxValue; uint expectedPackedValue2 = 0xFFF003FF; @@ -144,7 +146,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromBgr24() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -158,7 +160,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromGrey8() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -172,7 +174,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromGrey16() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -186,7 +188,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgb24() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -200,7 +202,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgb48() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -214,7 +216,7 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgba64() { // arrange - var rgba = default(Rgba1010102); + Rgba1010102 rgba = default; uint expectedPackedValue = uint.MaxValue; // act @@ -235,8 +237,8 @@ public class Rgba1010102Tests public void Rgba1010102_ToRgba32() { // arrange - var rgba = new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f); - var expected = new Rgba32(25, 0, 128, 0); + Rgba1010102 rgba = new(0.1f, -0.3f, 0.5f, -0.7f); + Rgba32 expected = new(25, 0, 128, 0); // act Rgba32 actual = default; @@ -245,4 +247,14 @@ public class Rgba1010102Tests // assert Assert.Equal(expected, actual); } + + [Fact] + public void Rgba1010102_PixelInformation() + { + PixelTypeInfo info = Rgba1010102.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 64903f65bb..6154773e85 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -18,12 +20,12 @@ public class Rgba32Tests [Fact] public void AreEqual() { - var color1 = new Rgba32(0, 0, 0); - var color2 = new Rgba32(0, 0, 0, 1F); - var color3 = Rgba32.ParseHex("#000"); - var color4 = Rgba32.ParseHex("#000F"); - var color5 = Rgba32.ParseHex("#000000"); - var color6 = Rgba32.ParseHex("#000000FF"); + Rgba32 color1 = new(0, 0, 0); + Rgba32 color2 = new(0, 0, 0, 1F); + Rgba32 color3 = Rgba32.ParseHex("#000"); + Rgba32 color4 = Rgba32.ParseHex("#000F"); + Rgba32 color5 = Rgba32.ParseHex("#000000"); + Rgba32 color6 = Rgba32.ParseHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -38,11 +40,11 @@ public class Rgba32Tests [Fact] public void AreNotEqual() { - var color1 = new Rgba32(255, 0, 0, 255); - var color2 = new Rgba32(0, 0, 0, 255); - var color3 = Rgba32.ParseHex("#000"); - var color4 = Rgba32.ParseHex("#000000"); - var color5 = Rgba32.ParseHex("#FF000000"); + Rgba32 color1 = new(255, 0, 0, 255); + Rgba32 color2 = new(0, 0, 0, 255); + Rgba32 color3 = Rgba32.ParseHex("#000"); + Rgba32 color4 = Rgba32.ParseHex("#000000"); + Rgba32 color5 = Rgba32.ParseHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -56,25 +58,25 @@ public class Rgba32Tests [Fact] public void ConstructorAssignsProperties() { - var color1 = new Rgba32(1, .1f, .133f, .864f); + Rgba32 color1 = new(1, .1f, .133f, .864f); Assert.Equal(255, color1.R); Assert.Equal((byte)Math.Round(.1f * 255), color1.G); Assert.Equal((byte)Math.Round(.133f * 255), color1.B); Assert.Equal((byte)Math.Round(.864f * 255), color1.A); - var color2 = new Rgba32(1, .1f, .133f); + Rgba32 color2 = new(1, .1f, .133f); Assert.Equal(255, color2.R); Assert.Equal(Math.Round(.1f * 255), color2.G); Assert.Equal(Math.Round(.133f * 255), color2.B); Assert.Equal(255, color2.A); - var color4 = new Rgba32(new Vector3(1, .1f, .133f)); + Rgba32 color4 = new(new Vector3(1, .1f, .133f)); Assert.Equal(255, color4.R); Assert.Equal(Math.Round(.1f * 255), color4.G); Assert.Equal(Math.Round(.133f * 255), color4.B); Assert.Equal(255, color4.A); - var color5 = new Rgba32(new Vector4(1, .1f, .133f, .5f)); + Rgba32 color5 = new(new Vector4(1, .1f, .133f, .5f)); Assert.Equal(255, color5.R); Assert.Equal(Math.Round(.1f * 255), color5.G); Assert.Equal(Math.Round(.133f * 255), color5.B); @@ -88,7 +90,7 @@ public class Rgba32Tests public void FromAndToHex() { // 8 digit hex matches css4 spec. RRGGBBAA - var color = Rgba32.ParseHex("#AABBCCDD"); // 170, 187, 204, 221 + Rgba32 color = Rgba32.ParseHex("#AABBCCDD"); // 170, 187, 204, 221 Assert.Equal(170, color.R); Assert.Equal(187, color.G); Assert.Equal(204, color.B); @@ -111,7 +113,7 @@ public class Rgba32Tests [Fact] public unsafe void ByteLayout() { - var color = new Rgba32(1, 2, 3, 4); + Rgba32 color = new(1, 2, 3, 4); byte* colorBase = (byte*)&color; Assert.Equal(1, colorBase[0]); Assert.Equal(2, colorBase[1]); @@ -146,7 +148,7 @@ public class Rgba32Tests public void Rgba32_ToScaledVector4() { // arrange - var rgba = new Rgba32(Vector4.One); + Rgba32 rgba = new(Vector4.One); // act Vector4 actual = rgba.ToScaledVector4(); @@ -162,8 +164,8 @@ public class Rgba32Tests public void Rgba32_FromScaledVector4() { // arrange - var rgba = new Rgba32(Vector4.One); - var actual = default(Rgba32); + Rgba32 rgba = new(Vector4.One); + Rgba32 actual = default; uint expected = 0xFFFFFFFF; // act @@ -185,9 +187,9 @@ public class Rgba32Tests public void Rgba32_ToRgba32() { // arrange - var rgba = new Rgba32(+0.1f, -0.3f, +0.5f, -0.7f); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); + Rgba32 rgba = new(+0.1f, -0.3f, +0.5f, -0.7f); + Rgba32 actual = default; + Rgba32 expected = new(0x1a, 0, 0x80, 0); // act actual.FromRgba32(rgba); @@ -200,9 +202,9 @@ public class Rgba32Tests public void Rgba32_FromRgba32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Rgba32); - var expected = new Rgba32(0x1a, 0, 0x80, 0); + Rgba32 rgba = default; + Rgba32 actual = default; + Rgba32 expected = new(0x1a, 0, 0x80, 0); // act rgba.FromRgba32(expected); @@ -216,9 +218,9 @@ public class Rgba32Tests public void Rgba32_FromBgra32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Bgra32); - var expected = new Bgra32(0x1a, 0, 0x80, 0); + Rgba32 rgba = default; + Bgra32 actual = default; + Bgra32 expected = new(0x1a, 0, 0x80, 0); // act rgba.FromBgra32(expected); @@ -232,9 +234,9 @@ public class Rgba32Tests public void Rgba32_FromAbgr32_ToRgba32() { // arrange - var rgba = default(Rgba32); - var actual = default(Abgr32); - var expected = new Abgr32(0x1a, 0, 0x80, 0); + Rgba32 rgba = default; + Abgr32 actual = default; + Abgr32 expected = new(0x1a, 0, 0x80, 0); // act rgba.FromAbgr32(expected); @@ -248,9 +250,9 @@ public class Rgba32Tests public void Rgba32_FromArgb32_ToArgb32() { // arrange - var rgba = default(Rgba32); - var actual = default(Argb32); - var expected = new Argb32(0x1a, 0, 0x80, 0); + Rgba32 rgba = default; + Argb32 actual = default; + Argb32 expected = new(0x1a, 0, 0x80, 0); // act rgba.FromArgb32(expected); @@ -264,9 +266,9 @@ public class Rgba32Tests public void Rgba32_FromRgb48() { // arrange - var input = default(Rgba32); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + Rgba32 input = default; + Rgb48 actual = default; + Rgb48 expected = new(65535, 0, 65535); // act input.FromRgb48(expected); @@ -280,9 +282,9 @@ public class Rgba32Tests public void Rgba32_FromRgba64() { // arrange - var input = default(Rgba32); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + Rgba32 input = default; + Rgba64 actual = default; + Rgba64 expected = new(65535, 0, 65535, 0); // act input.FromRgba64(expected); @@ -296,7 +298,7 @@ public class Rgba32Tests public void Rgba32_FromBgra5551() { // arrange - var rgb = default(Rgba32); + Rgba32 rgb = default; uint expected = 0xFFFFFFFF; // act @@ -305,4 +307,14 @@ public class Rgba32Tests // assert Assert.Equal(expected, rgb.PackedValue); } + + [Fact] + public void Rgba32_PixelInformation() + { + PixelTypeInfo info = Rgba32.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index f60ed8a529..e9b61c1e3a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -38,7 +40,7 @@ public class Rgba64Tests public void Rgba64_ToScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var short2 = new Rgba64(r, g, b, a); + Rgba64 short2 = new(r, g, b, a); float max = ushort.MaxValue; float rr = r / max; @@ -63,7 +65,7 @@ public class Rgba64Tests public void Rgba64_FromScaledVector4(ushort r, ushort g, ushort b, ushort a) { // arrange - var source = new Rgba64(r, g, b, a); + Rgba64 source = new(r, g, b, a); // act Vector4 scaled = source.ToScaledVector4(); @@ -78,8 +80,8 @@ public class Rgba64Tests [Fact] public void Rgba64_Clamping() { - var zero = default(Rgba64); - var one = default(Rgba64); + Rgba64 zero = default; + Rgba64 one = default; zero.FromVector4(Vector4.One * -1234.0f); one.FromVector4(Vector4.One * 1234.0f); Assert.Equal(Vector4.Zero, zero.ToVector4()); @@ -90,9 +92,9 @@ public class Rgba64Tests public void Rgba64_ToRgba32() { // arrange - var rgba64 = new Rgba64(5140, 9766, 19532, 29555); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 76, 115); + Rgba64 rgba64 = new(5140, 9766, 19532, 29555); + Rgba32 actual = default; + Rgba32 expected = new(20, 38, 76, 115); // act rgba64.ToRgba32(ref actual); @@ -105,7 +107,7 @@ public class Rgba64Tests public void Rgba64_FromBgra5551() { // arrange - var rgba = default(Rgba64); + Rgba64 rgba = default; ushort expected = ushort.MaxValue; // act @@ -121,8 +123,8 @@ public class Rgba64Tests [Fact] public void Equality_WhenTrue() { - var c1 = new Rgba64(100, 2000, 3000, 40000); - var c2 = new Rgba64(100, 2000, 3000, 40000); + Rgba64 c1 = new(100, 2000, 3000, 40000); + Rgba64 c2 = new(100, 2000, 3000, 40000); Assert.True(c1.Equals(c2)); Assert.True(c1.GetHashCode() == c2.GetHashCode()); @@ -131,9 +133,9 @@ public class Rgba64Tests [Fact] public void Equality_WhenFalse() { - var c1 = new Rgba64(100, 2000, 3000, 40000); - var c2 = new Rgba64(101, 2000, 3000, 40000); - var c3 = new Rgba64(100, 2000, 3000, 40001); + Rgba64 c1 = new(100, 2000, 3000, 40000); + Rgba64 c2 = new(101, 2000, 3000, 40000); + Rgba64 c3 = new(100, 2000, 3000, 40001); Assert.False(c1.Equals(c2)); Assert.False(c2.Equals(c3)); @@ -143,8 +145,8 @@ public class Rgba64Tests [Fact] public void Rgba64_FromRgba32() { - var source = new Rgba32(20, 38, 76, 115); - var expected = new Rgba64(5140, 9766, 19532, 29555); + Rgba32 source = new(20, 38, 76, 115); + Rgba64 expected = new(5140, 9766, 19532, 29555); Rgba64 actual = default; actual.FromRgba32(source); @@ -155,9 +157,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Rgba32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Rgba32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Rgba32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -165,9 +167,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Bgra32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Bgra32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Bgra32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -175,9 +177,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Argb32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Argb32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Argb32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -185,9 +187,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Abgr32() { - var expected = new Rgba64(5140, 9766, 19532, 29555); - var source = new Abgr32(20, 38, 76, 115); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, 29555); + Abgr32 source = new(20, 38, 76, 115); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -195,9 +197,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Rgb24() { - var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); - var source = new Rgb24(20, 38, 76); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, ushort.MaxValue); + Rgb24 source = new(20, 38, 76); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -205,9 +207,9 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Bgr24() { - var expected = new Rgba64(5140, 9766, 19532, ushort.MaxValue); - var source = new Bgr24(20, 38, 76); - var actual = new Rgba64(source); + Rgba64 expected = new(5140, 9766, 19532, ushort.MaxValue); + Bgr24 source = new(20, 38, 76); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -215,11 +217,11 @@ public class Rgba64Tests [Fact] public void ConstructFrom_Vector4() { - var source = new Vector4(0f, 0.2f, 0.5f, 1f); + Vector4 source = new(0f, 0.2f, 0.5f, 1f); Rgba64 expected = default; expected.FromScaledVector4(source); - var actual = new Rgba64(source); + Rgba64 actual = new(source); Assert.Equal(expected, actual); } @@ -228,11 +230,11 @@ public class Rgba64Tests public void ToRgba32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Rgba32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Rgba32 expected = new(20, 38, 76, 115); // act - var actual = source.ToRgba32(); + Rgba32 actual = source.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -242,11 +244,11 @@ public class Rgba64Tests public void ToBgra32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Bgra32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Bgra32 expected = new(20, 38, 76, 115); // act - var actual = source.ToBgra32(); + Bgra32 actual = source.ToBgra32(); // assert Assert.Equal(expected, actual); @@ -256,11 +258,11 @@ public class Rgba64Tests public void ToArgb32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Argb32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Argb32 expected = new(20, 38, 76, 115); // act - var actual = source.ToArgb32(); + Argb32 actual = source.ToArgb32(); // assert Assert.Equal(expected, actual); @@ -270,11 +272,11 @@ public class Rgba64Tests public void ToAbgr32_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Abgr32(20, 38, 76, 115); + Rgba64 source = new(5140, 9766, 19532, 29555); + Abgr32 expected = new(20, 38, 76, 115); // act - var actual = source.ToAbgr32(); + Abgr32 actual = source.ToAbgr32(); // assert Assert.Equal(expected, actual); @@ -284,11 +286,11 @@ public class Rgba64Tests public void ToRgb24_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Rgb24(20, 38, 76); + Rgba64 source = new(5140, 9766, 19532, 29555); + Rgb24 expected = new(20, 38, 76); // act - var actual = source.ToRgb24(); + Rgb24 actual = source.ToRgb24(); // assert Assert.Equal(expected, actual); @@ -298,13 +300,23 @@ public class Rgba64Tests public void ToBgr24_Retval() { // arrange - var source = new Rgba64(5140, 9766, 19532, 29555); - var expected = new Bgr24(20, 38, 76); + Rgba64 source = new(5140, 9766, 19532, 29555); + Bgr24 expected = new(20, 38, 76); // act - var actual = source.ToBgr24(); + Bgr24 actual = source.ToBgr24(); // assert Assert.Equal(expected, actual); } + + [Fact] + public void Rgba64_PixelInformation() + { + PixelTypeInfo info = Rgba64.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index ac6d2e3ca5..ba30b0bfe8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -19,12 +20,12 @@ public class RgbaVectorTests [Fact] public void AreEqual() { - var color1 = new RgbaVector(0, 0, 0F); - var color2 = new RgbaVector(0, 0, 0, 1F); - var color3 = RgbaVector.FromHex("#000"); - var color4 = RgbaVector.FromHex("#000F"); - var color5 = RgbaVector.FromHex("#000000"); - var color6 = RgbaVector.FromHex("#000000FF"); + RgbaVector color1 = new(0, 0, 0F); + RgbaVector color2 = new(0, 0, 0, 1F); + RgbaVector color3 = RgbaVector.FromHex("#000"); + RgbaVector color4 = RgbaVector.FromHex("#000F"); + RgbaVector color5 = RgbaVector.FromHex("#000000"); + RgbaVector color6 = RgbaVector.FromHex("#000000FF"); Assert.Equal(color1, color2); Assert.Equal(color1, color3); @@ -39,11 +40,11 @@ public class RgbaVectorTests [Fact] public void AreNotEqual() { - var color1 = new RgbaVector(1, 0, 0, 1); - var color2 = new RgbaVector(0, 0, 0, 1); - var color3 = RgbaVector.FromHex("#000"); - var color4 = RgbaVector.FromHex("#000000"); - var color5 = RgbaVector.FromHex("#FF000000"); + RgbaVector color1 = new(1, 0, 0, 1); + RgbaVector color2 = new(0, 0, 0, 1); + RgbaVector color3 = RgbaVector.FromHex("#000"); + RgbaVector color4 = RgbaVector.FromHex("#000000"); + RgbaVector color5 = RgbaVector.FromHex("#FF000000"); Assert.NotEqual(color1, color2); Assert.NotEqual(color1, color3); @@ -57,13 +58,13 @@ public class RgbaVectorTests [Fact] public void ConstructorAssignsProperties() { - var color1 = new RgbaVector(1, .1F, .133F, .864F); + RgbaVector color1 = new(1, .1F, .133F, .864F); Assert.Equal(1F, color1.R); Assert.Equal(.1F, color1.G); Assert.Equal(.133F, color1.B); Assert.Equal(.864F, color1.A); - var color2 = new RgbaVector(1, .1f, .133f); + RgbaVector color2 = new(1, .1f, .133f); Assert.Equal(1F, color2.R); Assert.Equal(.1F, color2.G); Assert.Equal(.133F, color2.B); @@ -76,7 +77,7 @@ public class RgbaVectorTests [Fact] public void FromAndToHex() { - var color = RgbaVector.FromHex("#AABBCCDD"); + RgbaVector color = RgbaVector.FromHex("#AABBCCDD"); Assert.Equal(170 / 255F, color.R); Assert.Equal(187 / 255F, color.G); Assert.Equal(204 / 255F, color.B); @@ -104,7 +105,7 @@ public class RgbaVectorTests [Fact] public void FloatLayout() { - var color = new RgbaVector(1F, 2, 3, 4); + RgbaVector color = new(1F, 2, 3, 4); Vector4 colorBase = Unsafe.As(ref Unsafe.Add(ref color, 0)); float[] ordered = new float[4]; colorBase.CopyTo(ordered); @@ -119,9 +120,9 @@ public class RgbaVectorTests public void RgbaVector_FromRgb48() { // arrange - var input = default(RgbaVector); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + RgbaVector input = default; + Rgb48 actual = default; + Rgb48 expected = new(65535, 0, 65535); // act input.FromRgb48(expected); @@ -135,9 +136,9 @@ public class RgbaVectorTests public void RgbaVector_FromRgba64() { // arrange - var input = default(RgbaVector); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + RgbaVector input = default; + Rgba64 actual = default; + Rgba64 expected = new(65535, 0, 65535, 0); // act input.FromRgba64(expected); @@ -151,7 +152,7 @@ public class RgbaVectorTests public void RgbaVector_FromBgra5551() { // arrange - var rgb = default(RgbaVector); + RgbaVector rgb = default; Vector4 expected = Vector4.One; // act @@ -165,7 +166,7 @@ public class RgbaVectorTests public void RgbaVector_FromGrey16() { // arrange - var rgba = default(RgbaVector); + RgbaVector rgba = default; Vector4 expected = Vector4.One; // act @@ -179,7 +180,7 @@ public class RgbaVectorTests public void RgbaVector_FromGrey8() { // arrange - var rgba = default(RgbaVector); + RgbaVector rgba = default; Vector4 expected = Vector4.One; // act @@ -204,4 +205,14 @@ public class RgbaVectorTests Assert.Equal(srcColor, cloneColor); } + + [Fact] + public void RgbaVector_PixelInformation() + { + PixelTypeInfo info = RgbaVector.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Float, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 8fc080d818..27631cbc78 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -51,7 +53,7 @@ public class Short2Tests public void Short2_ToScaledVector4() { // arrange - var short2 = new Short2(Vector2.One * 0x7FFF); + Short2 short2 = new(Vector2.One * 0x7FFF); // act Vector4 actual = short2.ToScaledVector4(); @@ -67,8 +69,8 @@ public class Short2Tests public void Short2_FromScaledVector4() { // arrange - var pixel = default(Short2); - var short2 = new Short2(Vector2.One * 0x7FFF); + Short2 pixel = default; + Short2 short2 = new(Vector2.One * 0x7FFF); const ulong expected = 0x7FFF7FFF; // act @@ -84,9 +86,9 @@ public class Short2Tests public void Short2_ToRgba32() { // arrange - var short2 = new Short2(127.5f, -5.3f); - var actual = default(Rgba32); - var expected = new Rgba32(128, 127, 0, 255); + Short2 short2 = new(127.5f, -5.3f); + Rgba32 actual = default; + Rgba32 expected = new(128, 127, 0, 255); // act short2.ToRgba32(ref actual); @@ -99,9 +101,9 @@ public class Short2Tests public void Short2_FromRgba32_ToRgba32() { // arrange - var short2 = default(Short2); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); + Short2 short2 = default; + Rgba32 actual = default; + Rgba32 expected = new(20, 38, 0, 255); // act short2.FromRgba32(expected); @@ -115,9 +117,9 @@ public class Short2Tests public void Short2_FromRgb48() { // arrange - var input = default(Short2); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 65535, 0); + Short2 input = default; + Rgb48 actual = default; + Rgb48 expected = new(65535, 65535, 0); // act input.FromRgb48(expected); @@ -131,9 +133,9 @@ public class Short2Tests public void Short2_FromRgba64() { // arrange - var input = default(Short2); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 65535, 0, 65535); + Short2 input = default; + Rgba64 actual = default; + Rgba64 expected = new(65535, 65535, 0, 65535); // act input.FromRgba64(expected); @@ -147,7 +149,7 @@ public class Short2Tests public void Short2_FromBgra5551() { // arrange - var short2 = default(Short2); + Short2 short2 = default; // act short2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); @@ -159,4 +161,14 @@ public class Short2Tests Assert.Equal(0, actual.Z); Assert.Equal(1, actual.W); } + + [Fact] + public void Short2_PixelInformation() + { + PixelTypeInfo info = Short2.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(2, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index c420627034..8d853f0593 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Numerics; +using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -12,8 +14,8 @@ public class Short4Tests [Fact] public void Short4_PackedValues() { - var shortValue1 = new Short4(11547, 12653, 29623, 193); - var shortValue2 = new Short4(0.1f, -0.3f, 0.5f, -0.7f); + Short4 shortValue1 = new(11547, 12653, 29623, 193); + Short4 shortValue2 = new(0.1f, -0.3f, 0.5f, -0.7f); Assert.Equal(0x00c173b7316d2d1bUL, shortValue1.PackedValue); Assert.Equal(18446462598732840960, shortValue2.PackedValue); @@ -38,7 +40,7 @@ public class Short4Tests public void Short4_ToScaledVector4() { // arrange - var short4 = new Short4(Vector4.One * 0x7FFF); + Short4 short4 = new(Vector4.One * 0x7FFF); // act Vector4 actual = short4.ToScaledVector4(); @@ -54,12 +56,12 @@ public class Short4Tests public void Short4_FromScaledVector4() { // arrange - var short4 = new Short4(Vector4.One * 0x7FFF); + Short4 short4 = new(Vector4.One * 0x7FFF); Vector4 scaled = short4.ToScaledVector4(); const long expected = 0x7FFF7FFF7FFF7FFF; // act - var pixel = default(Short4); + Short4 pixel = default; pixel.FromScaledVector4(scaled); // assert @@ -70,12 +72,12 @@ public class Short4Tests public void Short4_Clamping() { // arrange - var short1 = new Short4(Vector4.One * 1234567.0f); - var short2 = new Short4(Vector4.One * -1234567.0f); + Short4 short1 = new(Vector4.One * 1234567.0f); + Short4 short2 = new(Vector4.One * -1234567.0f); // act - var vector1 = short1.ToVector4(); - var vector2 = short2.ToVector4(); + Vector4 vector1 = short1.ToVector4(); + Vector4 vector2 = short2.ToVector4(); // assert Assert.Equal(Vector4.One * 0x7FFF, vector1); @@ -86,9 +88,9 @@ public class Short4Tests public void Short4_ToRgba32() { // arrange - var shortValue = new Short4(11547, 12653, 29623, 193); - var actual = default(Rgba32); - var expected = new Rgba32(172, 177, 243, 128); + Short4 shortValue = new(11547, 12653, 29623, 193); + Rgba32 actual = default; + Rgba32 expected = new(172, 177, 243, 128); // act shortValue.ToRgba32(ref actual); @@ -101,9 +103,9 @@ public class Short4Tests public void Short4_FromRgba32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Rgba32); - var expected = new Rgba32(20, 38, 0, 255); + Short4 short4 = default; + Rgba32 actual = default; + Rgba32 expected = new(20, 38, 0, 255); // act short4.FromRgba32(expected); @@ -117,9 +119,9 @@ public class Short4Tests public void Short4_FromBgra32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Bgra32); - var expected = new Bgra32(20, 38, 0, 255); + Short4 short4 = default; + Bgra32 actual = default; + Bgra32 expected = new(20, 38, 0, 255); // act short4.FromBgra32(expected); @@ -135,9 +137,9 @@ public class Short4Tests public void Short4_FromArgb32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Argb32); - var expected = new Argb32(20, 38, 0, 255); + Short4 short4 = default; + Argb32 actual = default; + Argb32 expected = new(20, 38, 0, 255); // act short4.FromArgb32(expected); @@ -153,9 +155,9 @@ public class Short4Tests public void Short4_FromAbgrb32_ToRgba32() { // arrange - var short4 = default(Short4); - var actual = default(Abgr32); - var expected = new Abgr32(20, 38, 0, 255); + Short4 short4 = default; + Abgr32 actual = default; + Abgr32 expected = new(20, 38, 0, 255); // act short4.FromAbgr32(expected); @@ -171,9 +173,9 @@ public class Short4Tests public void Short4_FromRgb48_ToRgb48() { // arrange - var input = default(Short4); - var actual = default(Rgb48); - var expected = new Rgb48(65535, 0, 65535); + Short4 input = default; + Rgb48 actual = default; + Rgb48 expected = new(65535, 0, 65535); // act input.FromRgb48(expected); @@ -187,9 +189,9 @@ public class Short4Tests public void Short4_FromRgba64_ToRgba64() { // arrange - var input = default(Short4); - var actual = default(Rgba64); - var expected = new Rgba64(65535, 0, 65535, 0); + Short4 input = default; + Rgba64 actual = default; + Rgba64 expected = new(65535, 0, 65535, 0); // act input.FromRgba64(expected); @@ -203,7 +205,7 @@ public class Short4Tests public void Short4_FromBgra5551() { // arrange - var short4 = default(Short4); + Short4 short4 = default; Vector4 expected = Vector4.One; // act @@ -212,4 +214,14 @@ public class Short4Tests // assert Assert.Equal(expected, short4.ToScaledVector4()); } + + [Fact] + public void Short4_PixelInformation() + { + PixelTypeInfo info = Short4.GetPixelTypeInfo(); + Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); + Assert.Equal(4, info.ComponentCount); + Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + } } diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 5cc35b43ed..75e3b693ce 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -12,8 +12,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Bytes_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -24,8 +24,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Floats_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -36,8 +36,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Vector4_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(new Vector4(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F)); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -48,8 +48,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Vector3_Produce_Equal_Scaled_Component_OutPut() { - var color = new Rgba32(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F); + Rgba32 color = new(new Vector3(24 / 255F, 48 / 255F, 96 / 255F)); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -60,8 +60,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_From_Hex_Produce_Equal_Scaled_Component_OutPut() { - var color = Rgba32.ParseHex("183060C0"); - var colorVector = RgbaVector.FromHex("183060C0"); + Rgba32 color = Rgba32.ParseHex("183060C0"); + RgbaVector colorVector = RgbaVector.FromHex("183060C0"); Assert.Equal(color.R, (byte)(colorVector.R * 255)); Assert.Equal(color.G, (byte)(colorVector.G * 255)); @@ -72,8 +72,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_To_Vector4_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Assert.Equal(color.ToVector4(), colorVector.ToVector4()); } @@ -81,8 +81,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_To_RgbaBytes_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); Rgba32 rgba = default; Rgba32 rgbaVector = default; @@ -95,8 +95,8 @@ public class UnPackedPixelTests [Fact] public void Color_Types_To_Hex_Produce_Equal_OutPut() { - var color = new Rgba32(24, 48, 96, 192); - var colorVector = new RgbaVector(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); + Rgba32 color = new(24, 48, 96, 192); + RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); // 183060C0 Assert.Equal(color.ToHex(), colorVector.ToHex()); diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 465a219701..a4232a9688 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -263,7 +263,7 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public struct TestPixelForAgnosticDecode : IPixel { - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); public PixelOperations CreatePixelOperations() => new(); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs index 5fb3501e36..ccb149ca32 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Numerics; @@ -85,7 +85,7 @@ public abstract partial class TestImageProvider : IXunitSerializable private static TPixel GetBottomRightColor() { TPixel bottomRightColor = default; - bottomRightColor.FromVector4(new Vector4(1f, 0f, 1f, 0.5f)); + bottomRightColor.FromScaledVector4(new Vector4(1f, 0f, 1f, 0.5f)); return bottomRightColor; } } From 75b9d88a48a82f6b760f38a6e95d40170c83c937 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 11 Dec 2023 09:18:07 +0000 Subject: [PATCH 102/219] Bump actions/setup-dotnet from 3 to 4 Bumps [actions/setup-dotnet](https://github.com/actions/setup-dotnet) from 3 to 4. - [Release notes](https://github.com/actions/setup-dotnet/releases) - [Commits](https://github.com/actions/setup-dotnet/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/setup-dotnet dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-and-test.yml | 4 ++-- .github/workflows/code-coverage.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 7c7791347d..75bcb8a256 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -89,14 +89,14 @@ jobs: - name: DotNet Setup if: ${{ matrix.options.sdk-preview != true }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 8.0.x - name: DotNet Setup Preview if: ${{ matrix.options.sdk-preview == true }} - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 8.0.x diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 7624e86b67..62b6477ee6 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -55,7 +55,7 @@ jobs: restore-keys: ${{ runner.os }}-nuget- - name: DotNet Setup - uses: actions/setup-dotnet@v3 + uses: actions/setup-dotnet@v4 with: dotnet-version: | 8.0.x From c7f18c8a6f18051ab3cb1b9fed90442a5530e062 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Dec 2023 19:28:34 +1000 Subject: [PATCH 103/219] Use info for color conversion --- src/ImageSharp/Color/Color.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 99458d58a1..3af3e04f07 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; @@ -124,7 +125,9 @@ public readonly partial struct Color : IEquatable { return new((L16)(object)pixel); } - else if (Unsafe.SizeOf() <= Unsafe.SizeOf()) + + PixelTypeInfo info = TPixel.GetPixelTypeInfo(); + if (info.ComponentPrecision <= PixelComponentPrecision.Byte) { Rgba32 p = default; pixel.ToRgba32(ref p); From ad1b0e6dadba957fa924d500900a7213bee717d3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Dec 2023 22:01:55 +1000 Subject: [PATCH 104/219] Fix handling gif encoding for global palettes. (#2614) * Handle global ani with 256 palette and no trans * Bump diff for windows --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 19 ++++++++++++------- .../Formats/Gif/MetadataExtensions.cs | 3 +++ .../Formats/Png/PngEncoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 4 +++- .../Images/Input/Gif/global-256-no-trans.gif | 3 +++ 5 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 tests/Images/Input/Gif/global-256-no-trans.gif diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 9988848d11..1215768e4b 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -103,7 +103,14 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { // We avoid dithering by default to preserve the original colors. int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); - this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex); + if (transparencyIndex >= 0 || gifMetadata.GlobalColorTable.Value.Length < 256) + { + this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex); + } + else + { + this.quantizer = KnownQuantizers.Octree; + } } else { @@ -198,19 +205,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals private static GifFrameMetadata GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) where TPixel : unmanaged, IPixel { + GifFrameMetadata? metadata = null; if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) { - return (GifFrameMetadata)gif.DeepClone(); + metadata = (GifFrameMetadata)gif.DeepClone(); } - - GifFrameMetadata? metadata = null; - if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) + else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) { AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); metadata = GifFrameMetadata.FromAnimatedMetadata(ani); } - - if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) + else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) { AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); metadata = GifFrameMetadata.FromAnimatedMetadata(ani); diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 42602f2c78..ad06462e77 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -82,6 +82,9 @@ public static partial class MetadataExtensions // has a local palette with 256 colors and is not transparent we should use 'Source'. bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency); + // If the color table is global and frame has no transparency. Consider it 'Source' also. + blendSource |= source.ColorTableMode == GifColorTableMode.Global && !source.HasTransparency; + return new() { ColorTable = source.LocalColorTable, diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index c81b7eb6cd..e70854b082 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -499,7 +499,7 @@ public partial class PngEncoderTests // TODO: Find a better way to compare. // The image has been visually checked but the quantization pattern used in the png encoder // means we cannot use an exact comparison nor replicate using the quantizing processor. - ImageComparer.TolerantPercentage(0.46f).VerifySimilarity(output, image); + ImageComparer.TolerantPercentage(0.613f).VerifySimilarity(output, image); GifMetadata gif = image.Metadata.GetGifMetadata(); PngMetadata png = output.Metadata.GetPngMetadata(); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index b628529028..8aa95d3496 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -488,6 +488,7 @@ public static class TestImages public const string MixedDisposal = "Gif/mixed-disposal.gif"; public const string M4nb = "Gif/m4nb.gif"; public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif"; + public const string Global256NoTrans = "Gif/global-256-no-trans.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -535,7 +536,8 @@ public static class TestImages Issues.Issue2450_B, Issues.BadDescriptorWidth, Issues.Issue1530, - Bit18RGBCube + Bit18RGBCube, + Global256NoTrans }; } diff --git a/tests/Images/Input/Gif/global-256-no-trans.gif b/tests/Images/Input/Gif/global-256-no-trans.gif new file mode 100644 index 0000000000..1afa0d21d7 --- /dev/null +++ b/tests/Images/Input/Gif/global-256-no-trans.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce8ed23b4e21328886f5aa7579079123ff6401efdf65e162e565b056ffddab56 +size 669286 From 51193111a1549b37fe7ea57c7e707945f31b662a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 11 Dec 2023 22:24:35 +1000 Subject: [PATCH 105/219] Fix handling gif encoding for global palettes - Main (#2615) * Handle dedup of local palette of 256 length * handle when foreground overhangs bottom of background * prevent potential overflow * reduce to a single par of clamping operations * correctly calculate Rect when negative target set * Handle global ani with 256 palette and no trans * Bump diff for windows --------- Co-authored-by: Scott Williams Co-authored-by: Scott Williams <166440+tocsoft@users.noreply.github.com> --- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 19 ++++++++++++------- .../Formats/Gif/MetadataExtensions.cs | 3 +++ .../Formats/Png/PngEncoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 4 +++- .../Images/Input/Gif/global-256-no-trans.gif | 3 +++ 5 files changed, 22 insertions(+), 9 deletions(-) create mode 100644 tests/Images/Input/Gif/global-256-no-trans.gif diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 9988848d11..1215768e4b 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -103,7 +103,14 @@ internal sealed class GifEncoderCore : IImageEncoderInternals { // We avoid dithering by default to preserve the original colors. int transparencyIndex = GetTransparentIndex(quantized, frameMetadata); - this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex); + if (transparencyIndex >= 0 || gifMetadata.GlobalColorTable.Value.Length < 256) + { + this.quantizer = new PaletteQuantizer(gifMetadata.GlobalColorTable.Value, new() { Dither = null }, transparencyIndex); + } + else + { + this.quantizer = KnownQuantizers.Octree; + } } else { @@ -198,19 +205,17 @@ internal sealed class GifEncoderCore : IImageEncoderInternals private static GifFrameMetadata GetGifFrameMetadata(ImageFrame frame, int transparencyIndex) where TPixel : unmanaged, IPixel { + GifFrameMetadata? metadata = null; if (frame.Metadata.TryGetGifMetadata(out GifFrameMetadata? gif)) { - return (GifFrameMetadata)gif.DeepClone(); + metadata = (GifFrameMetadata)gif.DeepClone(); } - - GifFrameMetadata? metadata = null; - if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) + else if (frame.Metadata.TryGetPngMetadata(out PngFrameMetadata? png)) { AnimatedImageFrameMetadata ani = png.ToAnimatedImageFrameMetadata(); metadata = GifFrameMetadata.FromAnimatedMetadata(ani); } - - if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) + else if (frame.Metadata.TryGetWebpFrameMetadata(out WebpFrameMetadata? webp)) { AnimatedImageFrameMetadata ani = webp.ToAnimatedImageFrameMetadata(); metadata = GifFrameMetadata.FromAnimatedMetadata(ani); diff --git a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs index 42602f2c78..ad06462e77 100644 --- a/src/ImageSharp/Formats/Gif/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Gif/MetadataExtensions.cs @@ -82,6 +82,9 @@ public static partial class MetadataExtensions // has a local palette with 256 colors and is not transparent we should use 'Source'. bool blendSource = source.DisposalMethod == GifDisposalMethod.RestoreToBackground || (source.LocalColorTable?.Length == 256 && !source.HasTransparency); + // If the color table is global and frame has no transparency. Consider it 'Source' also. + blendSource |= source.ColorTableMode == GifColorTableMode.Global && !source.HasTransparency; + return new() { ColorTable = source.LocalColorTable, diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index c81b7eb6cd..e70854b082 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -499,7 +499,7 @@ public partial class PngEncoderTests // TODO: Find a better way to compare. // The image has been visually checked but the quantization pattern used in the png encoder // means we cannot use an exact comparison nor replicate using the quantizing processor. - ImageComparer.TolerantPercentage(0.46f).VerifySimilarity(output, image); + ImageComparer.TolerantPercentage(0.613f).VerifySimilarity(output, image); GifMetadata gif = image.Metadata.GetGifMetadata(); PngMetadata png = output.Metadata.GetPngMetadata(); diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index b628529028..8aa95d3496 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -488,6 +488,7 @@ public static class TestImages public const string MixedDisposal = "Gif/mixed-disposal.gif"; public const string M4nb = "Gif/m4nb.gif"; public const string Bit18RGBCube = "Gif/18-bit_RGB_Cube.gif"; + public const string Global256NoTrans = "Gif/global-256-no-trans.gif"; // Test images from https://github.com/robert-ancell/pygif/tree/master/test-suite public const string ZeroSize = "Gif/image-zero-size.gif"; @@ -535,7 +536,8 @@ public static class TestImages Issues.Issue2450_B, Issues.BadDescriptorWidth, Issues.Issue1530, - Bit18RGBCube + Bit18RGBCube, + Global256NoTrans }; } diff --git a/tests/Images/Input/Gif/global-256-no-trans.gif b/tests/Images/Input/Gif/global-256-no-trans.gif new file mode 100644 index 0000000000..1afa0d21d7 --- /dev/null +++ b/tests/Images/Input/Gif/global-256-no-trans.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ce8ed23b4e21328886f5aa7579079123ff6401efdf65e162e565b056ffddab56 +size 669286 From d1c231bb85876ed40d569a5f29497fb5e68c5cda Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 12 Dec 2023 08:08:51 +1000 Subject: [PATCH 106/219] Rename property, use int. --- src/ImageSharp/Color/Color.cs | 2 +- src/ImageSharp/Formats/PixelTypeInfo.cs | 8 ++++---- src/ImageSharp/PixelFormats/PixelComponentPrecision.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/A8Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/L16Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/L8Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/La16Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/La32Tests.cs | 2 +- .../ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs | 2 +- .../ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs | 2 +- .../PixelFormats/NormalizedShort2Tests.cs | 2 +- .../PixelFormats/NormalizedShort4Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs | 2 +- tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs | 2 +- 32 files changed, 35 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 3af3e04f07..7110090501 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -127,7 +127,7 @@ public readonly partial struct Color : IEquatable } PixelTypeInfo info = TPixel.GetPixelTypeInfo(); - if (info.ComponentPrecision <= PixelComponentPrecision.Byte) + if (info.MaxComponentPrecision <= PixelComponentPrecision.Byte) { Rgba32 p = default; pixel.ToRgba32(ref p); diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/Formats/PixelTypeInfo.cs index 0c2a4f4c86..170ffcfae6 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/Formats/PixelTypeInfo.cs @@ -26,12 +26,12 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) /// /// Gets the count of the color components /// - public byte ComponentCount { get; init; } + public int ComponentCount { get; init; } /// - /// Gets the pixel component precision. + /// Gets the maximum precision of components within the pixel. /// - public PixelComponentPrecision? ComponentPrecision { get; init; } + public PixelComponentPrecision? MaxComponentPrecision { get; init; } /// /// Gets the pixel alpha transparency behavior. @@ -48,7 +48,7 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) { BitsPerPixel = Unsafe.SizeOf() * 8, ComponentCount = componentCount, - ComponentPrecision = componentPrecision, + MaxComponentPrecision = componentPrecision, AlphaRepresentation = pixelAlphaRepresentation }; } diff --git a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs index 8b12986578..3480ac76ed 100644 --- a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs +++ b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs @@ -4,7 +4,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// -/// Provides enumeration of the maximum precision of individual components within a pixel format. +/// Provides enumeration of the precision of individual components within a pixel format. /// public enum PixelComponentPrecision { diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index 008bc652c2..518aa203d9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -118,6 +118,6 @@ public class A8Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index 3c185383c3..dbe02e9868 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -153,6 +153,6 @@ public class Abgr32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index f6b818fb58..fd8ee144ba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -151,6 +151,6 @@ public class Argb32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 6861dab41c..78c58e5c26 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -136,6 +136,6 @@ public class Bgr24Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index b68b943251..68f9532252 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -258,6 +258,6 @@ public class Bgr565Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index 17d184d1a5..e92fcf1d36 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -153,6 +153,6 @@ public class Bgra32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 648ef79d5a..1af84c0c84 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -254,6 +254,6 @@ public class Bgra4444Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index e32ec665e2..a0926d4ddf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -280,6 +280,6 @@ public class Bgra5551Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index ce5752fbad..5b456459ea 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -247,6 +247,6 @@ public class Byte4Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index cbff2b85e9..9c546e2f0c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -76,6 +76,6 @@ public class HalfSingleTests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 98a5cb0bff..4f84d60871 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -98,6 +98,6 @@ public class HalfVector2Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 48d10f1c1e..33f0173d2e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -89,6 +89,6 @@ public class HalfVector4Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 18481712a0..0c0cdbe3bf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -168,6 +168,6 @@ public class L16Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index 80dc36fa39..d8bce0640e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -263,7 +263,7 @@ public class L8Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index c3d8a873ac..46e7457a5f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -267,7 +267,7 @@ public class La16Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index 17e10e15d8..65aa8b1c9c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -174,6 +174,6 @@ public class La32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index a09454f5bc..999ddb9341 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -90,6 +90,6 @@ public class NormalizedByte2Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.SByte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.SByte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index aa0136b37d..64a996453b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -240,6 +240,6 @@ public class NormalizedByte4Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.SByte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.SByte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 6ac18fa089..e6d4ae98d9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -94,6 +94,6 @@ public class NormalizedShort2Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index fcab7318b6..cd684311a9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -241,6 +241,6 @@ public class NormalizedShort4Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index c5c534655a..bf3ff6416a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -92,6 +92,6 @@ public class Rg32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index dbb2e8f03d..c69c757b59 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -139,6 +139,6 @@ public class Rgb24Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 04bbaf7f78..dda5af9fb3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -84,6 +84,6 @@ public class Rgb48Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 678ac2274e..5b0e4c2874 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -255,6 +255,6 @@ public class Rgba1010102Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 6154773e85..d1ad4c304a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -315,6 +315,6 @@ public class Rgba32Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index e9b61c1e3a..3dc5804604 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -317,6 +317,6 @@ public class Rgba64Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index ba30b0bfe8..968e274e23 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -213,6 +213,6 @@ public class RgbaVectorTests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Float, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Float, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 27631cbc78..7afe61b025 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -169,6 +169,6 @@ public class Short2Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 8d853f0593..bdde5cd8f9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -222,6 +222,6 @@ public class Short4Tests Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.ComponentPrecision); + Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); } } From 9672d48bcc1bf858200c8f321b64b68986196e0d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 12 Dec 2023 22:54:32 +1000 Subject: [PATCH 107/219] Fix Ssse3 Path decode --- src/ImageSharp/Formats/Png/Filters/PaethFilter.cs | 6 +++--- tests/ImageSharp.Tests/Formats/Png/PngDecoderFilterTests.cs | 3 +++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs index b8324a0809..59c903c1dd 100644 --- a/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs +++ b/src/ImageSharp/Formats/Png/Filters/PaethFilter.cs @@ -35,9 +35,9 @@ internal static class PaethFilter // row: a d // The Paeth function predicts d to be whichever of a, b, or c is nearest to // p = a + b - c. - if (Sse2.IsSupported && bytesPerPixel is 4) + if (Ssse3.IsSupported && bytesPerPixel is 4) { - DecodeSse3(scanline, previousScanline); + DecodeSsse3(scanline, previousScanline); } else if (AdvSimd.Arm64.IsSupported && bytesPerPixel is 4) { @@ -50,7 +50,7 @@ internal static class PaethFilter } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void DecodeSse3(Span scanline, Span previousScanline) + private static void DecodeSsse3(Span scanline, Span previousScanline) { ref byte scanBaseRef = ref MemoryMarshal.GetReference(scanline); ref byte prevBaseRef = ref MemoryMarshal.GetReference(previousScanline); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderFilterTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderFilterTests.cs index ec6de0dfab..f5c42c734b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderFilterTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderFilterTests.cs @@ -170,6 +170,9 @@ public class PngDecoderFilterTests [Fact] public void PaethFilter_WithHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPaethFilterTest, HwIntrinsics.AllowAll); + [Fact] + public void PaethFilter_WithoutSsse3_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPaethFilterTest, HwIntrinsics.DisableSSSE3); + [Fact] public void PaethFilter_WithoutHardwareIntrinsics_Works() => FeatureTestRunner.RunWithHwIntrinsicsFeature(RunPaethFilterTest, HwIntrinsics.DisableHWIntrinsic); } From 768c1cbe7a65841b7c3f991cc54b3e478912e595 Mon Sep 17 00:00:00 2001 From: Jean-Sebastien Carle <29762210+jscarle@users.noreply.github.com> Date: Thu, 14 Dec 2023 10:02:28 -0500 Subject: [PATCH 108/219] Update WebpFormat.cs Adjusted casing of Webp format name. --- src/ImageSharp/Formats/Webp/WebpFormat.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/WebpFormat.cs b/src/ImageSharp/Formats/Webp/WebpFormat.cs index 197041234e..1764182c51 100644 --- a/src/ImageSharp/Formats/Webp/WebpFormat.cs +++ b/src/ImageSharp/Formats/Webp/WebpFormat.cs @@ -18,7 +18,7 @@ public sealed class WebpFormat : IImageFormat public static WebpFormat Instance { get; } = new WebpFormat(); /// - public string Name => "Webp"; + public string Name => "WEBP"; /// public string DefaultMimeType => "image/webp"; From 715297c905f5e8a3199f157f67d0359a4f8ab6ad Mon Sep 17 00:00:00 2001 From: Mark Lagendijk Date: Mon, 18 Dec 2023 09:49:12 +0100 Subject: [PATCH 109/219] Fix WebP animation speed bug `Milliseconds` is the milli seconds component of the TimeSpan, `TotalMilliseconds` is the entire TimeSpan expressed as milliseconds. Example, Timespan of 3.5 seconds: * `Milliseconds`: 500 * `TotalMilliseconds`: 3500 --- src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index 422ad6bc7c..cd1b5d5905 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -48,7 +48,7 @@ public class WebpFrameMetadata : IDeepCloneable internal static WebpFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) => new() { - FrameDelay = (uint)metadata.Duration.Milliseconds, + FrameDelay = (uint)metadata.Duration.TotalMilliseconds, BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendMethod.Source : WebpBlendMethod.Over, DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose }; From 51cd84eb2f2354544eacdc8a2db3748daebe2fa2 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 18 Dec 2023 09:05:53 +0000 Subject: [PATCH 110/219] Bump actions/upload-artifact from 3 to 4 Bumps [actions/upload-artifact](https://github.com/actions/upload-artifact) from 3 to 4. - [Release notes](https://github.com/actions/upload-artifact/releases) - [Commits](https://github.com/actions/upload-artifact/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/upload-artifact dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-and-test.yml | 2 +- .github/workflows/code-coverage.yml | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 75bcb8a256..51765be6ea 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -132,7 +132,7 @@ jobs: XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Export Failed Output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 62b6477ee6..53eef45042 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -74,7 +74,7 @@ jobs: XUNIT_PATH: .\tests\ImageSharp.Tests # Required for xunit - name: Export Failed Output - uses: actions/upload-artifact@v3 + uses: actions/upload-artifact@v4 if: failure() with: name: actual_output_${{ runner.os }}_${{ matrix.options.framework }}${{ matrix.options.runtime }}.zip From 6570fc6c7446d594e20bc8c85e1404d48fc59862 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 1 Jan 2024 13:22:33 +1000 Subject: [PATCH 111/219] Update WebpFrameMetadata.cs --- src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs index 422ad6bc7c..cd1b5d5905 100644 --- a/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs +++ b/src/ImageSharp/Formats/Webp/WebpFrameMetadata.cs @@ -48,7 +48,7 @@ public class WebpFrameMetadata : IDeepCloneable internal static WebpFrameMetadata FromAnimatedMetadata(AnimatedImageFrameMetadata metadata) => new() { - FrameDelay = (uint)metadata.Duration.Milliseconds, + FrameDelay = (uint)metadata.Duration.TotalMilliseconds, BlendMethod = metadata.BlendMode == FrameBlendMode.Source ? WebpBlendMethod.Source : WebpBlendMethod.Over, DisposalMethod = metadata.DisposalMode == FrameDisposalMode.RestoreToBackground ? WebpDisposalMethod.RestoreToBackground : WebpDisposalMethod.DoNotDispose }; From 6b6b474892d1a4ecfc450c3b61323d11a68145ab Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 2 Jan 2024 22:05:58 +1000 Subject: [PATCH 112/219] Introduce PixelComponentInfo + simplify Color --- src/ImageSharp/Color/Color.Conversions.cs | 240 --------------- src/ImageSharp/Color/Color.NamedColors.cs | 288 +++++++++--------- src/ImageSharp/Color/Color.cs | 145 ++++----- src/ImageSharp/Formats/AnimationUtilities.cs | 4 +- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 10 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 9 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 4 +- .../Formats/Png/PngScanlineProcessor.cs | 2 +- .../BlackIsZero1TiffColor{TPixel}.cs | 4 +- .../WhiteIsZero1TiffColor{TPixel}.cs | 4 +- .../Formats/Webp/BitWriter/BitWriterBase.cs | 3 +- .../Formats/Webp/WebpAnimationDecoder.cs | 2 +- .../Formats/Webp/WebpDecoderCore.cs | 2 +- src/ImageSharp/ImageInfo.cs | 2 +- src/ImageSharp/Image{TPixel}.cs | 1 - src/ImageSharp/PixelFormats/IPixel.cs | 1 - .../PixelFormats/PixelComponentInfo.cs | 111 +++++++ .../PixelFormats/PixelComponentPrecision.cs | 38 ++- .../PixelFormats/PixelImplementations/A8.cs | 3 +- .../PixelImplementations/Abgr32.cs | 19 +- .../PixelImplementations/Argb32.cs | 19 +- .../PixelImplementations/Bgr24.cs | 19 +- .../PixelImplementations/Bgr565.cs | 3 +- .../PixelImplementations/Bgra32.cs | 19 +- .../PixelImplementations/Bgra4444.cs | 3 +- .../PixelImplementations/Bgra5551.cs | 3 +- .../PixelImplementations/Byte4.cs | 3 +- .../PixelImplementations/HalfSingle.cs | 3 +- .../PixelImplementations/HalfVector2.cs | 3 +- .../PixelImplementations/HalfVector4.cs | 3 +- .../PixelFormats/PixelImplementations/L16.cs | 3 +- .../PixelFormats/PixelImplementations/L8.cs | 3 +- .../PixelFormats/PixelImplementations/La16.cs | 3 +- .../PixelFormats/PixelImplementations/La32.cs | 3 +- .../PixelImplementations/NormalizedByte2.cs | 3 +- .../PixelImplementations/NormalizedByte4.cs | 3 +- .../PixelImplementations/NormalizedShort2.cs | 3 +- .../PixelImplementations/NormalizedShort4.cs | 3 +- .../PixelFormats/PixelImplementations/Rg32.cs | 3 +- .../PixelImplementations/Rgb24.cs | 19 +- .../PixelImplementations/Rgb48.cs | 3 +- .../PixelImplementations/Rgba1010102.cs | 3 +- .../PixelImplementations/Rgba32.cs | 19 +- .../PixelImplementations/Rgba64.cs | 19 +- .../PixelImplementations/RgbaVector.cs | 3 +- .../PixelImplementations/Short2.cs | 3 +- .../PixelImplementations/Short4.cs | 3 +- .../PixelFormats/PixelOperations{TPixel}.cs | 1 - .../PixelTypeInfo.cs | 29 +- .../Filters/LomographProcessor{TPixel}.cs | 2 +- .../Filters/PolaroidProcessor{TPixel}.cs | 4 +- .../General/GetSetPixel.cs | 2 +- .../Processing/BokehBlur.cs | 2 +- .../Processing/Diffuse.cs | 4 +- .../Processing/GaussianBlur.cs | 2 +- .../Processing/Rotate.cs | 2 +- .../ImageSharp.Benchmarks/Processing/Skew.cs | 2 +- .../Color/ColorTests.CastFrom.cs | 28 +- .../Color/ColorTests.CastTo.cs | 32 +- .../Color/ColorTests.ConstructFrom.cs | 28 +- tests/ImageSharp.Tests/Color/ColorTests.cs | 128 +++----- tests/ImageSharp.Tests/Color/RgbaDouble.cs | 180 +++++++++++ .../Drawing/DrawImageTests.cs | 4 +- .../Formats/Png/PngDecoderTests.cs | 4 +- .../Formats/Png/PngEncoderTests.cs | 7 +- .../PhotometricInterpretationTestBase.cs | 2 +- .../Tiff/TiffEncoderMultiframeTests.cs | 20 +- .../ImageFrameCollectionTests.Generic.cs | 2 +- .../ImageFrameCollectionTests.NonGeneric.cs | 13 +- .../ImageSharp.Tests/Image/ImageFrameTests.cs | 4 +- .../Image/ImageTests.LoadPixelData.cs | 49 ++- .../Image/ImageTests.WrapMemory.cs | 16 +- tests/ImageSharp.Tests/Image/ImageTests.cs | 6 +- tests/ImageSharp.Tests/ImageInfoTests.cs | 2 +- .../ImageSharp.Tests/PixelFormats/A8Tests.cs | 9 +- .../PixelFormats/Abgr32Tests.cs | 12 +- .../PixelFormats/Argb32Tests.cs | 12 +- .../PixelFormats/Bgr24Tests.cs | 11 +- .../PixelFormats/Bgr565Tests.cs | 11 +- .../PixelFormats/Bgra32Tests.cs | 12 +- .../PixelFormats/Bgra4444Tests.cs | 12 +- .../PixelFormats/Bgra5551Tests.cs | 12 +- .../PixelFormats/Byte4Tests.cs | 12 +- .../PixelFormats/HalfSingleTests.cs | 9 +- .../PixelFormats/HalfVector2Tests.cs | 10 +- .../PixelFormats/HalfVector4Tests.cs | 12 +- .../ImageSharp.Tests/PixelFormats/L16Tests.cs | 9 +- .../ImageSharp.Tests/PixelFormats/L8Tests.cs | 9 +- .../PixelFormats/La16Tests.cs | 10 +- .../PixelFormats/La32Tests.cs | 10 +- .../PixelFormats/NormalizedByte2Tests.cs | 10 +- .../PixelFormats/NormalizedByte4Tests.cs | 12 +- .../PixelFormats/NormalizedShort2Tests.cs | 10 +- .../PixelFormats/NormalizedShort4Tests.cs | 12 +- .../PixelFormats/PixelBlenderTests.cs | 42 +-- .../PixelFormats/Rg32Tests.cs | 10 +- .../PixelFormats/Rgb24Tests.cs | 11 +- .../PixelFormats/Rgb48Tests.cs | 11 +- .../PixelFormats/Rgba1010102Tests.cs | 12 +- .../PixelFormats/Rgba32Tests.cs | 12 +- .../PixelFormats/Rgba64Tests.cs | 12 +- .../PixelFormats/RgbaVectorTests.cs | 12 +- .../PixelFormats/Short2Tests.cs | 10 +- .../PixelFormats/Short4Tests.cs | 12 +- .../Quantization/WuQuantizerTests.cs | 4 +- tests/ImageSharp.Tests/TestFormat.cs | 2 +- .../ImageProviders/SolidProvider.cs | 2 +- 107 files changed, 1021 insertions(+), 991 deletions(-) delete mode 100644 src/ImageSharp/Color/Color.Conversions.cs create mode 100644 src/ImageSharp/PixelFormats/PixelComponentInfo.cs rename src/ImageSharp/{Formats => PixelFormats}/PixelTypeInfo.cs (65%) create mode 100644 tests/ImageSharp.Tests/Color/RgbaDouble.cs diff --git a/src/ImageSharp/Color/Color.Conversions.cs b/src/ImageSharp/Color/Color.Conversions.cs deleted file mode 100644 index 309ab83ec4..0000000000 --- a/src/ImageSharp/Color/Color.Conversions.cs +++ /dev/null @@ -1,240 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp; - -/// -/// Contains constructors and implicit conversion methods. -/// -public readonly partial struct Color -{ - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgba64 pixel) - { - this.data = pixel; - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgb48 pixel) - { - this.data = new Rgba64(pixel.R, pixel.G, pixel.B, ushort.MaxValue); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(La32 pixel) - { - this.data = new Rgba64(pixel.L, pixel.L, pixel.L, pixel.A); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(L16 pixel) - { - this.data = new Rgba64(pixel.PackedValue, pixel.PackedValue, pixel.PackedValue, ushort.MaxValue); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgba32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Argb32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Bgra32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Abgr32 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Rgb24 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Bgr24 pixel) - { - this.data = new Rgba64(pixel); - this.boxedHighPrecisionPixel = null; - } - - /// - /// Initializes a new instance of the struct. - /// - /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] - public Color(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); - this.boxedHighPrecisionPixel = new RgbaVector(vector.X, vector.Y, vector.Z, vector.W); - this.data = default; - } - - /// - /// Converts a to . - /// - /// The . - /// The . - public static explicit operator Vector4(Color color) => color.ToScaledVector4(); - - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static explicit operator Color(Vector4 source) => new(source); - - [MethodImpl(InliningOptions.ShortMethod)] - internal Rgba32 ToRgba32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToRgba32(); - } - - Rgba32 value = default; - this.boxedHighPrecisionPixel.ToRgba32(ref value); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Bgra32 ToBgra32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToBgra32(); - } - - Bgra32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Argb32 ToArgb32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToArgb32(); - } - - Argb32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Abgr32 ToAbgr32() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToAbgr32(); - } - - Abgr32 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Rgb24 ToRgb24() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToRgb24(); - } - - Rgb24 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Bgr24 ToBgr24() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToBgr24(); - } - - Bgr24 value = default; - value.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return value; - } - - [MethodImpl(InliningOptions.ShortMethod)] - internal Vector4 ToScaledVector4() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data.ToScaledVector4(); - } - - return this.boxedHighPrecisionPixel.ToScaledVector4(); - } -} diff --git a/src/ImageSharp/Color/Color.NamedColors.cs b/src/ImageSharp/Color/Color.NamedColors.cs index f8b4c90fd6..00130dd904 100644 --- a/src/ImageSharp/Color/Color.NamedColors.cs +++ b/src/ImageSharp/Color/Color.NamedColors.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.PixelFormats; + namespace SixLabors.ImageSharp; /// @@ -9,107 +11,107 @@ namespace SixLabors.ImageSharp; /// public readonly partial struct Color { - private static readonly Lazy> NamedColorsLookupLazy = new Lazy>(CreateNamedColorsLookup, true); + private static readonly Lazy> NamedColorsLookupLazy = new(CreateNamedColorsLookup, true); /// /// Represents a matching the W3C definition that has an hex value of #F0F8FF. /// - public static readonly Color AliceBlue = FromRgba(240, 248, 255, 255); + public static readonly Color AliceBlue = FromPixel(new Rgba32(240, 248, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAEBD7. /// - public static readonly Color AntiqueWhite = FromRgba(250, 235, 215, 255); + public static readonly Color AntiqueWhite = FromPixel(new Rgba32(250, 235, 215, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. /// - public static readonly Color Aqua = FromRgba(0, 255, 255, 255); + public static readonly Color Aqua = FromPixel(new Rgba32(0, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7FFFD4. /// - public static readonly Color Aquamarine = FromRgba(127, 255, 212, 255); + public static readonly Color Aquamarine = FromPixel(new Rgba32(127, 255, 212, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F0FFFF. /// - public static readonly Color Azure = FromRgba(240, 255, 255, 255); + public static readonly Color Azure = FromPixel(new Rgba32(240, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5F5DC. /// - public static readonly Color Beige = FromRgba(245, 245, 220, 255); + public static readonly Color Beige = FromPixel(new Rgba32(245, 245, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4C4. /// - public static readonly Color Bisque = FromRgba(255, 228, 196, 255); + public static readonly Color Bisque = FromPixel(new Rgba32(255, 228, 196, 255)); /// /// Represents a matching the W3C definition that has an hex value of #000000. /// - public static readonly Color Black = FromRgba(0, 0, 0, 255); + public static readonly Color Black = FromPixel(new Rgba32(0, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFEBCD. /// - public static readonly Color BlanchedAlmond = FromRgba(255, 235, 205, 255); + public static readonly Color BlanchedAlmond = FromPixel(new Rgba32(255, 235, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #0000FF. /// - public static readonly Color Blue = FromRgba(0, 0, 255, 255); + public static readonly Color Blue = FromPixel(new Rgba32(0, 0, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8A2BE2. /// - public static readonly Color BlueViolet = FromRgba(138, 43, 226, 255); + public static readonly Color BlueViolet = FromPixel(new Rgba32(138, 43, 226, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A52A2A. /// - public static readonly Color Brown = FromRgba(165, 42, 42, 255); + public static readonly Color Brown = FromPixel(new Rgba32(165, 42, 42, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DEB887. /// - public static readonly Color BurlyWood = FromRgba(222, 184, 135, 255); + public static readonly Color BurlyWood = FromPixel(new Rgba32(222, 184, 135, 255)); /// /// Represents a matching the W3C definition that has an hex value of #5F9EA0. /// - public static readonly Color CadetBlue = FromRgba(95, 158, 160, 255); + public static readonly Color CadetBlue = FromPixel(new Rgba32(95, 158, 160, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7FFF00. /// - public static readonly Color Chartreuse = FromRgba(127, 255, 0, 255); + public static readonly Color Chartreuse = FromPixel(new Rgba32(127, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D2691E. /// - public static readonly Color Chocolate = FromRgba(210, 105, 30, 255); + public static readonly Color Chocolate = FromPixel(new Rgba32(210, 105, 30, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF7F50. /// - public static readonly Color Coral = FromRgba(255, 127, 80, 255); + public static readonly Color Coral = FromPixel(new Rgba32(255, 127, 80, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6495ED. /// - public static readonly Color CornflowerBlue = FromRgba(100, 149, 237, 255); + public static readonly Color CornflowerBlue = FromPixel(new Rgba32(100, 149, 237, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF8DC. /// - public static readonly Color Cornsilk = FromRgba(255, 248, 220, 255); + public static readonly Color Cornsilk = FromPixel(new Rgba32(255, 248, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DC143C. /// - public static readonly Color Crimson = FromRgba(220, 20, 60, 255); + public static readonly Color Crimson = FromPixel(new Rgba32(220, 20, 60, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FFFF. @@ -119,27 +121,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #00008B. /// - public static readonly Color DarkBlue = FromRgba(0, 0, 139, 255); + public static readonly Color DarkBlue = FromPixel(new Rgba32(0, 0, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008B8B. /// - public static readonly Color DarkCyan = FromRgba(0, 139, 139, 255); + public static readonly Color DarkCyan = FromPixel(new Rgba32(0, 139, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B8860B. /// - public static readonly Color DarkGoldenrod = FromRgba(184, 134, 11, 255); + public static readonly Color DarkGoldenrod = FromPixel(new Rgba32(184, 134, 11, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A9A9A9. /// - public static readonly Color DarkGray = FromRgba(169, 169, 169, 255); + public static readonly Color DarkGray = FromPixel(new Rgba32(169, 169, 169, 255)); /// /// Represents a matching the W3C definition that has an hex value of #006400. /// - public static readonly Color DarkGreen = FromRgba(0, 100, 0, 255); + public static readonly Color DarkGreen = FromPixel(new Rgba32(0, 100, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A9A9A9. @@ -149,52 +151,52 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #BDB76B. /// - public static readonly Color DarkKhaki = FromRgba(189, 183, 107, 255); + public static readonly Color DarkKhaki = FromPixel(new Rgba32(189, 183, 107, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B008B. /// - public static readonly Color DarkMagenta = FromRgba(139, 0, 139, 255); + public static readonly Color DarkMagenta = FromPixel(new Rgba32(139, 0, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #556B2F. /// - public static readonly Color DarkOliveGreen = FromRgba(85, 107, 47, 255); + public static readonly Color DarkOliveGreen = FromPixel(new Rgba32(85, 107, 47, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF8C00. /// - public static readonly Color DarkOrange = FromRgba(255, 140, 0, 255); + public static readonly Color DarkOrange = FromPixel(new Rgba32(255, 140, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9932CC. /// - public static readonly Color DarkOrchid = FromRgba(153, 50, 204, 255); + public static readonly Color DarkOrchid = FromPixel(new Rgba32(153, 50, 204, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B0000. /// - public static readonly Color DarkRed = FromRgba(139, 0, 0, 255); + public static readonly Color DarkRed = FromPixel(new Rgba32(139, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E9967A. /// - public static readonly Color DarkSalmon = FromRgba(233, 150, 122, 255); + public static readonly Color DarkSalmon = FromPixel(new Rgba32(233, 150, 122, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8FBC8F. /// - public static readonly Color DarkSeaGreen = FromRgba(143, 188, 143, 255); + public static readonly Color DarkSeaGreen = FromPixel(new Rgba32(143, 188, 143, 255)); /// /// Represents a matching the W3C definition that has an hex value of #483D8B. /// - public static readonly Color DarkSlateBlue = FromRgba(72, 61, 139, 255); + public static readonly Color DarkSlateBlue = FromPixel(new Rgba32(72, 61, 139, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2F4F4F. /// - public static readonly Color DarkSlateGray = FromRgba(47, 79, 79, 255); + public static readonly Color DarkSlateGray = FromPixel(new Rgba32(47, 79, 79, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2F4F4F. @@ -204,27 +206,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #00CED1. /// - public static readonly Color DarkTurquoise = FromRgba(0, 206, 209, 255); + public static readonly Color DarkTurquoise = FromPixel(new Rgba32(0, 206, 209, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9400D3. /// - public static readonly Color DarkViolet = FromRgba(148, 0, 211, 255); + public static readonly Color DarkViolet = FromPixel(new Rgba32(148, 0, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF1493. /// - public static readonly Color DeepPink = FromRgba(255, 20, 147, 255); + public static readonly Color DeepPink = FromPixel(new Rgba32(255, 20, 147, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00BFFF. /// - public static readonly Color DeepSkyBlue = FromRgba(0, 191, 255, 255); + public static readonly Color DeepSkyBlue = FromPixel(new Rgba32(0, 191, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #696969. /// - public static readonly Color DimGray = FromRgba(105, 105, 105, 255); + public static readonly Color DimGray = FromPixel(new Rgba32(105, 105, 105, 255)); /// /// Represents a matching the W3C definition that has an hex value of #696969. @@ -234,62 +236,62 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #1E90FF. /// - public static readonly Color DodgerBlue = FromRgba(30, 144, 255, 255); + public static readonly Color DodgerBlue = FromPixel(new Rgba32(30, 144, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B22222. /// - public static readonly Color Firebrick = FromRgba(178, 34, 34, 255); + public static readonly Color Firebrick = FromPixel(new Rgba32(178, 34, 34, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFAF0. /// - public static readonly Color FloralWhite = FromRgba(255, 250, 240, 255); + public static readonly Color FloralWhite = FromPixel(new Rgba32(255, 250, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #228B22. /// - public static readonly Color ForestGreen = FromRgba(34, 139, 34, 255); + public static readonly Color ForestGreen = FromPixel(new Rgba32(34, 139, 34, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. /// - public static readonly Color Fuchsia = FromRgba(255, 0, 255, 255); + public static readonly Color Fuchsia = FromPixel(new Rgba32(255, 0, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DCDCDC. /// - public static readonly Color Gainsboro = FromRgba(220, 220, 220, 255); + public static readonly Color Gainsboro = FromPixel(new Rgba32(220, 220, 220, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F8F8FF. /// - public static readonly Color GhostWhite = FromRgba(248, 248, 255, 255); + public static readonly Color GhostWhite = FromPixel(new Rgba32(248, 248, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFD700. /// - public static readonly Color Gold = FromRgba(255, 215, 0, 255); + public static readonly Color Gold = FromPixel(new Rgba32(255, 215, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DAA520. /// - public static readonly Color Goldenrod = FromRgba(218, 165, 32, 255); + public static readonly Color Goldenrod = FromPixel(new Rgba32(218, 165, 32, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808080. /// - public static readonly Color Gray = FromRgba(128, 128, 128, 255); + public static readonly Color Gray = FromPixel(new Rgba32(128, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008000. /// - public static readonly Color Green = FromRgba(0, 128, 0, 255); + public static readonly Color Green = FromPixel(new Rgba32(0, 128, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #ADFF2F. /// - public static readonly Color GreenYellow = FromRgba(173, 255, 47, 255); + public static readonly Color GreenYellow = FromPixel(new Rgba32(173, 255, 47, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808080. @@ -299,82 +301,82 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #F0FFF0. /// - public static readonly Color Honeydew = FromRgba(240, 255, 240, 255); + public static readonly Color Honeydew = FromPixel(new Rgba32(240, 255, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF69B4. /// - public static readonly Color HotPink = FromRgba(255, 105, 180, 255); + public static readonly Color HotPink = FromPixel(new Rgba32(255, 105, 180, 255)); /// /// Represents a matching the W3C definition that has an hex value of #CD5C5C. /// - public static readonly Color IndianRed = FromRgba(205, 92, 92, 255); + public static readonly Color IndianRed = FromPixel(new Rgba32(205, 92, 92, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4B0082. /// - public static readonly Color Indigo = FromRgba(75, 0, 130, 255); + public static readonly Color Indigo = FromPixel(new Rgba32(75, 0, 130, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFF0. /// - public static readonly Color Ivory = FromRgba(255, 255, 240, 255); + public static readonly Color Ivory = FromPixel(new Rgba32(255, 255, 240, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F0E68C. /// - public static readonly Color Khaki = FromRgba(240, 230, 140, 255); + public static readonly Color Khaki = FromPixel(new Rgba32(240, 230, 140, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E6E6FA. /// - public static readonly Color Lavender = FromRgba(230, 230, 250, 255); + public static readonly Color Lavender = FromPixel(new Rgba32(230, 230, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF0F5. /// - public static readonly Color LavenderBlush = FromRgba(255, 240, 245, 255); + public static readonly Color LavenderBlush = FromPixel(new Rgba32(255, 240, 245, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7CFC00. /// - public static readonly Color LawnGreen = FromRgba(124, 252, 0, 255); + public static readonly Color LawnGreen = FromPixel(new Rgba32(124, 252, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFACD. /// - public static readonly Color LemonChiffon = FromRgba(255, 250, 205, 255); + public static readonly Color LemonChiffon = FromPixel(new Rgba32(255, 250, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #ADD8E6. /// - public static readonly Color LightBlue = FromRgba(173, 216, 230, 255); + public static readonly Color LightBlue = FromPixel(new Rgba32(173, 216, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F08080. /// - public static readonly Color LightCoral = FromRgba(240, 128, 128, 255); + public static readonly Color LightCoral = FromPixel(new Rgba32(240, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #E0FFFF. /// - public static readonly Color LightCyan = FromRgba(224, 255, 255, 255); + public static readonly Color LightCyan = FromPixel(new Rgba32(224, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAFAD2. /// - public static readonly Color LightGoldenrodYellow = FromRgba(250, 250, 210, 255); + public static readonly Color LightGoldenrodYellow = FromPixel(new Rgba32(250, 250, 210, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D3D3D3. /// - public static readonly Color LightGray = FromRgba(211, 211, 211, 255); + public static readonly Color LightGray = FromPixel(new Rgba32(211, 211, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #90EE90. /// - public static readonly Color LightGreen = FromRgba(144, 238, 144, 255); + public static readonly Color LightGreen = FromPixel(new Rgba32(144, 238, 144, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D3D3D3. @@ -384,27 +386,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #FFB6C1. /// - public static readonly Color LightPink = FromRgba(255, 182, 193, 255); + public static readonly Color LightPink = FromPixel(new Rgba32(255, 182, 193, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFA07A. /// - public static readonly Color LightSalmon = FromRgba(255, 160, 122, 255); + public static readonly Color LightSalmon = FromPixel(new Rgba32(255, 160, 122, 255)); /// /// Represents a matching the W3C definition that has an hex value of #20B2AA. /// - public static readonly Color LightSeaGreen = FromRgba(32, 178, 170, 255); + public static readonly Color LightSeaGreen = FromPixel(new Rgba32(32, 178, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #87CEFA. /// - public static readonly Color LightSkyBlue = FromRgba(135, 206, 250, 255); + public static readonly Color LightSkyBlue = FromPixel(new Rgba32(135, 206, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #778899. /// - public static readonly Color LightSlateGray = FromRgba(119, 136, 153, 255); + public static readonly Color LightSlateGray = FromPixel(new Rgba32(119, 136, 153, 255)); /// /// Represents a matching the W3C definition that has an hex value of #778899. @@ -414,27 +416,27 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #B0C4DE. /// - public static readonly Color LightSteelBlue = FromRgba(176, 196, 222, 255); + public static readonly Color LightSteelBlue = FromPixel(new Rgba32(176, 196, 222, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFE0. /// - public static readonly Color LightYellow = FromRgba(255, 255, 224, 255); + public static readonly Color LightYellow = FromPixel(new Rgba32(255, 255, 224, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FF00. /// - public static readonly Color Lime = FromRgba(0, 255, 0, 255); + public static readonly Color Lime = FromPixel(new Rgba32(0, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #32CD32. /// - public static readonly Color LimeGreen = FromRgba(50, 205, 50, 255); + public static readonly Color LimeGreen = FromPixel(new Rgba32(50, 205, 50, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FAF0E6. /// - public static readonly Color Linen = FromRgba(250, 240, 230, 255); + public static readonly Color Linen = FromPixel(new Rgba32(250, 240, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF00FF. @@ -444,237 +446,237 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #800000. /// - public static readonly Color Maroon = FromRgba(128, 0, 0, 255); + public static readonly Color Maroon = FromPixel(new Rgba32(128, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #66CDAA. /// - public static readonly Color MediumAquamarine = FromRgba(102, 205, 170, 255); + public static readonly Color MediumAquamarine = FromPixel(new Rgba32(102, 205, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #0000CD. /// - public static readonly Color MediumBlue = FromRgba(0, 0, 205, 255); + public static readonly Color MediumBlue = FromPixel(new Rgba32(0, 0, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #BA55D3. /// - public static readonly Color MediumOrchid = FromRgba(186, 85, 211, 255); + public static readonly Color MediumOrchid = FromPixel(new Rgba32(186, 85, 211, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9370DB. /// - public static readonly Color MediumPurple = FromRgba(147, 112, 219, 255); + public static readonly Color MediumPurple = FromPixel(new Rgba32(147, 112, 219, 255)); /// /// Represents a matching the W3C definition that has an hex value of #3CB371. /// - public static readonly Color MediumSeaGreen = FromRgba(60, 179, 113, 255); + public static readonly Color MediumSeaGreen = FromPixel(new Rgba32(60, 179, 113, 255)); /// /// Represents a matching the W3C definition that has an hex value of #7B68EE. /// - public static readonly Color MediumSlateBlue = FromRgba(123, 104, 238, 255); + public static readonly Color MediumSlateBlue = FromPixel(new Rgba32(123, 104, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FA9A. /// - public static readonly Color MediumSpringGreen = FromRgba(0, 250, 154, 255); + public static readonly Color MediumSpringGreen = FromPixel(new Rgba32(0, 250, 154, 255)); /// /// Represents a matching the W3C definition that has an hex value of #48D1CC. /// - public static readonly Color MediumTurquoise = FromRgba(72, 209, 204, 255); + public static readonly Color MediumTurquoise = FromPixel(new Rgba32(72, 209, 204, 255)); /// /// Represents a matching the W3C definition that has an hex value of #C71585. /// - public static readonly Color MediumVioletRed = FromRgba(199, 21, 133, 255); + public static readonly Color MediumVioletRed = FromPixel(new Rgba32(199, 21, 133, 255)); /// /// Represents a matching the W3C definition that has an hex value of #191970. /// - public static readonly Color MidnightBlue = FromRgba(25, 25, 112, 255); + public static readonly Color MidnightBlue = FromPixel(new Rgba32(25, 25, 112, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5FFFA. /// - public static readonly Color MintCream = FromRgba(245, 255, 250, 255); + public static readonly Color MintCream = FromPixel(new Rgba32(245, 255, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4E1. /// - public static readonly Color MistyRose = FromRgba(255, 228, 225, 255); + public static readonly Color MistyRose = FromPixel(new Rgba32(255, 228, 225, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFE4B5. /// - public static readonly Color Moccasin = FromRgba(255, 228, 181, 255); + public static readonly Color Moccasin = FromPixel(new Rgba32(255, 228, 181, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFDEAD. /// - public static readonly Color NavajoWhite = FromRgba(255, 222, 173, 255); + public static readonly Color NavajoWhite = FromPixel(new Rgba32(255, 222, 173, 255)); /// /// Represents a matching the W3C definition that has an hex value of #000080. /// - public static readonly Color Navy = FromRgba(0, 0, 128, 255); + public static readonly Color Navy = FromPixel(new Rgba32(0, 0, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FDF5E6. /// - public static readonly Color OldLace = FromRgba(253, 245, 230, 255); + public static readonly Color OldLace = FromPixel(new Rgba32(253, 245, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #808000. /// - public static readonly Color Olive = FromRgba(128, 128, 0, 255); + public static readonly Color Olive = FromPixel(new Rgba32(128, 128, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6B8E23. /// - public static readonly Color OliveDrab = FromRgba(107, 142, 35, 255); + public static readonly Color OliveDrab = FromPixel(new Rgba32(107, 142, 35, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFA500. /// - public static readonly Color Orange = FromRgba(255, 165, 0, 255); + public static readonly Color Orange = FromPixel(new Rgba32(255, 165, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF4500. /// - public static readonly Color OrangeRed = FromRgba(255, 69, 0, 255); + public static readonly Color OrangeRed = FromPixel(new Rgba32(255, 69, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DA70D6. /// - public static readonly Color Orchid = FromRgba(218, 112, 214, 255); + public static readonly Color Orchid = FromPixel(new Rgba32(218, 112, 214, 255)); /// /// Represents a matching the W3C definition that has an hex value of #EEE8AA. /// - public static readonly Color PaleGoldenrod = FromRgba(238, 232, 170, 255); + public static readonly Color PaleGoldenrod = FromPixel(new Rgba32(238, 232, 170, 255)); /// /// Represents a matching the W3C definition that has an hex value of #98FB98. /// - public static readonly Color PaleGreen = FromRgba(152, 251, 152, 255); + public static readonly Color PaleGreen = FromPixel(new Rgba32(152, 251, 152, 255)); /// /// Represents a matching the W3C definition that has an hex value of #AFEEEE. /// - public static readonly Color PaleTurquoise = FromRgba(175, 238, 238, 255); + public static readonly Color PaleTurquoise = FromPixel(new Rgba32(175, 238, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DB7093. /// - public static readonly Color PaleVioletRed = FromRgba(219, 112, 147, 255); + public static readonly Color PaleVioletRed = FromPixel(new Rgba32(219, 112, 147, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFEFD5. /// - public static readonly Color PapayaWhip = FromRgba(255, 239, 213, 255); + public static readonly Color PapayaWhip = FromPixel(new Rgba32(255, 239, 213, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFDAB9. /// - public static readonly Color PeachPuff = FromRgba(255, 218, 185, 255); + public static readonly Color PeachPuff = FromPixel(new Rgba32(255, 218, 185, 255)); /// /// Represents a matching the W3C definition that has an hex value of #CD853F. /// - public static readonly Color Peru = FromRgba(205, 133, 63, 255); + public static readonly Color Peru = FromPixel(new Rgba32(205, 133, 63, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFC0CB. /// - public static readonly Color Pink = FromRgba(255, 192, 203, 255); + public static readonly Color Pink = FromPixel(new Rgba32(255, 192, 203, 255)); /// /// Represents a matching the W3C definition that has an hex value of #DDA0DD. /// - public static readonly Color Plum = FromRgba(221, 160, 221, 255); + public static readonly Color Plum = FromPixel(new Rgba32(221, 160, 221, 255)); /// /// Represents a matching the W3C definition that has an hex value of #B0E0E6. /// - public static readonly Color PowderBlue = FromRgba(176, 224, 230, 255); + public static readonly Color PowderBlue = FromPixel(new Rgba32(176, 224, 230, 255)); /// /// Represents a matching the W3C definition that has an hex value of #800080. /// - public static readonly Color Purple = FromRgba(128, 0, 128, 255); + public static readonly Color Purple = FromPixel(new Rgba32(128, 0, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #663399. /// - public static readonly Color RebeccaPurple = FromRgba(102, 51, 153, 255); + public static readonly Color RebeccaPurple = FromPixel(new Rgba32(102, 51, 153, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF0000. /// - public static readonly Color Red = FromRgba(255, 0, 0, 255); + public static readonly Color Red = FromPixel(new Rgba32(255, 0, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #BC8F8F. /// - public static readonly Color RosyBrown = FromRgba(188, 143, 143, 255); + public static readonly Color RosyBrown = FromPixel(new Rgba32(188, 143, 143, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4169E1. /// - public static readonly Color RoyalBlue = FromRgba(65, 105, 225, 255); + public static readonly Color RoyalBlue = FromPixel(new Rgba32(65, 105, 225, 255)); /// /// Represents a matching the W3C definition that has an hex value of #8B4513. /// - public static readonly Color SaddleBrown = FromRgba(139, 69, 19, 255); + public static readonly Color SaddleBrown = FromPixel(new Rgba32(139, 69, 19, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FA8072. /// - public static readonly Color Salmon = FromRgba(250, 128, 114, 255); + public static readonly Color Salmon = FromPixel(new Rgba32(250, 128, 114, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F4A460. /// - public static readonly Color SandyBrown = FromRgba(244, 164, 96, 255); + public static readonly Color SandyBrown = FromPixel(new Rgba32(244, 164, 96, 255)); /// /// Represents a matching the W3C definition that has an hex value of #2E8B57. /// - public static readonly Color SeaGreen = FromRgba(46, 139, 87, 255); + public static readonly Color SeaGreen = FromPixel(new Rgba32(46, 139, 87, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFF5EE. /// - public static readonly Color SeaShell = FromRgba(255, 245, 238, 255); + public static readonly Color SeaShell = FromPixel(new Rgba32(255, 245, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #A0522D. /// - public static readonly Color Sienna = FromRgba(160, 82, 45, 255); + public static readonly Color Sienna = FromPixel(new Rgba32(160, 82, 45, 255)); /// /// Represents a matching the W3C definition that has an hex value of #C0C0C0. /// - public static readonly Color Silver = FromRgba(192, 192, 192, 255); + public static readonly Color Silver = FromPixel(new Rgba32(192, 192, 192, 255)); /// /// Represents a matching the W3C definition that has an hex value of #87CEEB. /// - public static readonly Color SkyBlue = FromRgba(135, 206, 235, 255); + public static readonly Color SkyBlue = FromPixel(new Rgba32(135, 206, 235, 255)); /// /// Represents a matching the W3C definition that has an hex value of #6A5ACD. /// - public static readonly Color SlateBlue = FromRgba(106, 90, 205, 255); + public static readonly Color SlateBlue = FromPixel(new Rgba32(106, 90, 205, 255)); /// /// Represents a matching the W3C definition that has an hex value of #708090. /// - public static readonly Color SlateGray = FromRgba(112, 128, 144, 255); + public static readonly Color SlateGray = FromPixel(new Rgba32(112, 128, 144, 255)); /// /// Represents a matching the W3C definition that has an hex value of #708090. @@ -684,81 +686,80 @@ public readonly partial struct Color /// /// Represents a matching the W3C definition that has an hex value of #FFFAFA. /// - public static readonly Color Snow = FromRgba(255, 250, 250, 255); + public static readonly Color Snow = FromPixel(new Rgba32(255, 250, 250, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00FF7F. /// - public static readonly Color SpringGreen = FromRgba(0, 255, 127, 255); + public static readonly Color SpringGreen = FromPixel(new Rgba32(0, 255, 127, 255)); /// /// Represents a matching the W3C definition that has an hex value of #4682B4. /// - public static readonly Color SteelBlue = FromRgba(70, 130, 180, 255); + public static readonly Color SteelBlue = FromPixel(new Rgba32(70, 130, 180, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D2B48C. /// - public static readonly Color Tan = FromRgba(210, 180, 140, 255); + public static readonly Color Tan = FromPixel(new Rgba32(210, 180, 140, 255)); /// /// Represents a matching the W3C definition that has an hex value of #008080. /// - public static readonly Color Teal = FromRgba(0, 128, 128, 255); + public static readonly Color Teal = FromPixel(new Rgba32(0, 128, 128, 255)); /// /// Represents a matching the W3C definition that has an hex value of #D8BFD8. /// - public static readonly Color Thistle = FromRgba(216, 191, 216, 255); + public static readonly Color Thistle = FromPixel(new Rgba32(216, 191, 216, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FF6347. /// - public static readonly Color Tomato = FromRgba(255, 99, 71, 255); + public static readonly Color Tomato = FromPixel(new Rgba32(255, 99, 71, 255)); /// /// Represents a matching the W3C definition that has an hex value of #00000000. /// - public static readonly Color Transparent = FromRgba(0, 0, 0, 0); + public static readonly Color Transparent = FromPixel(new Rgba32(0, 0, 0, 0)); /// /// Represents a matching the W3C definition that has an hex value of #40E0D0. /// - public static readonly Color Turquoise = FromRgba(64, 224, 208, 255); + public static readonly Color Turquoise = FromPixel(new Rgba32(64, 224, 208, 255)); /// /// Represents a matching the W3C definition that has an hex value of #EE82EE. /// - public static readonly Color Violet = FromRgba(238, 130, 238, 255); + public static readonly Color Violet = FromPixel(new Rgba32(238, 130, 238, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5DEB3. /// - public static readonly Color Wheat = FromRgba(245, 222, 179, 255); + public static readonly Color Wheat = FromPixel(new Rgba32(245, 222, 179, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFFFF. /// - public static readonly Color White = FromRgba(255, 255, 255, 255); + public static readonly Color White = FromPixel(new Rgba32(255, 255, 255, 255)); /// /// Represents a matching the W3C definition that has an hex value of #F5F5F5. /// - public static readonly Color WhiteSmoke = FromRgba(245, 245, 245, 255); + public static readonly Color WhiteSmoke = FromPixel(new Rgba32(245, 245, 245, 255)); /// /// Represents a matching the W3C definition that has an hex value of #FFFF00. /// - public static readonly Color Yellow = FromRgba(255, 255, 0, 255); + public static readonly Color Yellow = FromPixel(new Rgba32(255, 255, 0, 255)); /// /// Represents a matching the W3C definition that has an hex value of #9ACD32. /// - public static readonly Color YellowGreen = FromRgba(154, 205, 50, 255); + public static readonly Color YellowGreen = FromPixel(new Rgba32(154, 205, 50, 255)); private static Dictionary CreateNamedColorsLookup() - { - return new Dictionary(StringComparer.OrdinalIgnoreCase) + => new(StringComparer.OrdinalIgnoreCase) { { nameof(AliceBlue), AliceBlue }, { nameof(AntiqueWhite), AntiqueWhite }, @@ -910,5 +911,4 @@ public readonly partial struct Color { nameof(Yellow), Yellow }, { nameof(YellowGreen), YellowGreen } }; - } } diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 7110090501..ec19a86eb9 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; @@ -19,33 +18,24 @@ namespace SixLabors.ImageSharp; /// public readonly partial struct Color : IEquatable { - private readonly Rgba64 data; + private readonly Vector4 data; private readonly IPixel? boxedHighPrecisionPixel; + /// + /// Initializes a new instance of the struct. + /// + /// The containing the color information. [MethodImpl(InliningOptions.ShortMethod)] - private Color(byte r, byte g, byte b, byte a) - { - this.data = new Rgba64( - ColorNumerics.UpscaleFrom8BitTo16Bit(r), - ColorNumerics.UpscaleFrom8BitTo16Bit(g), - ColorNumerics.UpscaleFrom8BitTo16Bit(b), - ColorNumerics.UpscaleFrom8BitTo16Bit(a)); - - this.boxedHighPrecisionPixel = null; - } - - [MethodImpl(InliningOptions.ShortMethod)] - private Color(byte r, byte g, byte b) + private Color(Vector4 vector) { - this.data = new Rgba64( - ColorNumerics.UpscaleFrom8BitTo16Bit(r), - ColorNumerics.UpscaleFrom8BitTo16Bit(g), - ColorNumerics.UpscaleFrom8BitTo16Bit(b), - ushort.MaxValue); - + this.data = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); this.boxedHighPrecisionPixel = null; } + /// + /// Initializes a new instance of the struct. + /// + /// The pixel containing color information. [MethodImpl(InliningOptions.ShortMethod)] private Color(IPixel pixel) { @@ -53,6 +43,21 @@ public readonly partial struct Color : IEquatable this.data = default; } + /// + /// Converts a to . + /// + /// The . + /// The . + public static explicit operator Vector4(Color color) => color.ToScaledVector4(); + + /// + /// Converts an to . + /// + /// The . + /// The . + [MethodImpl(InliningOptions.ShortMethod)] + public static explicit operator Color(Vector4 source) => new(source); + /// /// Checks whether two structures are equal. /// @@ -77,27 +82,6 @@ public readonly partial struct Color : IEquatable [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(Color left, Color right) => !left.Equals(right); - /// - /// Creates a from RGBA bytes. - /// - /// The red component (0-255). - /// The green component (0-255). - /// The blue component (0-255). - /// The alpha component (0-255). - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromRgba(byte r, byte g, byte b, byte a) => new(r, g, b, a); - - /// - /// Creates a from RGB bytes. - /// - /// The red component (0-255). - /// The green component (0-255). - /// The blue component (0-255). - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromRgb(byte r, byte g, byte b) => new(r, g, b); - /// /// Creates a from the given . /// @@ -108,34 +92,45 @@ public readonly partial struct Color : IEquatable public static Color FromPixel(TPixel pixel) where TPixel : unmanaged, IPixel { - // Avoid boxing in case we can convert to Rgba64 safely and efficiently - if (typeof(TPixel) == typeof(Rgba64)) - { - return new((Rgba64)(object)pixel); - } - else if (typeof(TPixel) == typeof(Rgb48)) - { - return new((Rgb48)(object)pixel); - } - else if (typeof(TPixel) == typeof(La32)) + // Avoid boxing in case we can convert to Vector4 safely and efficiently + PixelTypeInfo info = TPixel.GetPixelTypeInfo(); + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) { - return new((La32)(object)pixel); + return new(pixel.ToScaledVector4()); } - else if (typeof(TPixel) == typeof(L16)) + else { - return new((L16)(object)pixel); + return new(pixel); } + } + /// + /// Bulk converts a span of a specified type to a span of . + /// + /// The pixel type to convert to. + /// The source pixel span. + /// The destination color span. + [MethodImpl(InliningOptions.ShortMethod)] + public static void FromPixel(ReadOnlySpan source, Span destination) + where TPixel : unmanaged, IPixel + { + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); + + // Avoid boxing in case we can convert to Vector4 safely and efficiently PixelTypeInfo info = TPixel.GetPixelTypeInfo(); - if (info.MaxComponentPrecision <= PixelComponentPrecision.Byte) + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) { - Rgba32 p = default; - pixel.ToRgba32(ref p); - return new(p); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = new(source[i].ToScaledVector4()); + } } else { - return new(pixel); + for (int i = 0; i < destination.Length; i++) + { + destination[i] = new(source[i]); + } } } @@ -154,8 +149,7 @@ public readonly partial struct Color : IEquatable public static Color ParseHex(string hex) { Rgba32 rgba = Rgba32.ParseHex(hex); - - return new Color(rgba); + return FromPixel(rgba); } /// @@ -177,7 +171,7 @@ public readonly partial struct Color : IEquatable if (Rgba32.TryParseHex(hex, out Rgba32 rgba)) { - result = new Color(rgba); + result = FromPixel(rgba); return true; } @@ -256,14 +250,15 @@ public readonly partial struct Color : IEquatable [MethodImpl(InliningOptions.ShortMethod)] public string ToHex() { + Rgba32 rgba = default; if (this.boxedHighPrecisionPixel is not null) { - Rgba32 rgba = default; this.boxedHighPrecisionPixel.ToRgba32(ref rgba); return rgba.ToHex(); } - return this.data.ToRgba32().ToHex(); + rgba.FromScaledVector4(this.data); + return rgba.ToHex(); } /// @@ -286,7 +281,7 @@ public readonly partial struct Color : IEquatable if (this.boxedHighPrecisionPixel is null) { pixel = default; - pixel.FromRgba64(this.data); + pixel.FromScaledVector4(this.data); return pixel; } @@ -305,7 +300,8 @@ public readonly partial struct Color : IEquatable public static void ToPixel(ReadOnlySpan source, Span destination) where TPixel : unmanaged, IPixel { - // TODO: Investigate bulk operations utilizing configuration parameter here. + // We cannot use bulk pixel operations here as there is no guarantee that the source colors are + // created from pixel formats which fit into the unboxed vector data. Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); for (int i = 0; i < source.Length; i++) { @@ -319,7 +315,7 @@ public readonly partial struct Color : IEquatable { if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null) { - return this.data.PackedValue == other.data.PackedValue; + return this.data == other.data; } return this.boxedHighPrecisionPixel?.Equals(other.boxedHighPrecisionPixel) == true; @@ -334,9 +330,20 @@ public readonly partial struct Color : IEquatable { if (this.boxedHighPrecisionPixel is null) { - return this.data.PackedValue.GetHashCode(); + return this.data.GetHashCode(); } return this.boxedHighPrecisionPixel.GetHashCode(); } + + [MethodImpl(InliningOptions.ShortMethod)] + private Vector4 ToScaledVector4() + { + if (this.boxedHighPrecisionPixel is null) + { + return this.data; + } + + return this.boxedHighPrecisionPixel.ToScaledVector4(); + } } diff --git a/src/ImageSharp/Formats/AnimationUtilities.cs b/src/ImageSharp/Formats/AnimationUtilities.cs index 288f3d1329..4605d4daa7 100644 --- a/src/ImageSharp/Formats/AnimationUtilities.cs +++ b/src/ImageSharp/Formats/AnimationUtilities.cs @@ -50,7 +50,7 @@ internal static class AnimationUtilities Span next = buffers.GetSpan().Slice(currentFrame.Width * 2, currentFrame.Width); Span result = buffers.GetSpan()[(currentFrame.Width * 3)..]; - Rgba32 bg = replacement; + Rgba32 bg = replacement.ToPixel(); int top = int.MinValue; int bottom = int.MaxValue; @@ -232,7 +232,7 @@ internal static class AnimationUtilities ref Rgba32 r = ref Unsafe.Add(ref MemoryMarshal.GetReference(result), x); bool peq = c.Rgba == (previousFrame != null ? p.Rgba : bg.Rgba); - Rgba32 val = (blend & peq) ? replacement : c; + Rgba32 val = (blend & peq) ? bg : c; peq &= nextFrame == null || (n.Rgba >> 24 >= c.Rgba >> 24); r = val; diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index aecbbbbc71..8916da6e0e 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -711,10 +711,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals Color[] colorTable = new Color[this.imageDescriptor.LocalColorTableSize]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(this.currentLocalColorTable!.GetSpan()[..this.currentLocalColorTableSize]); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); gifMeta.LocalColorTable = colorTable; } @@ -789,10 +786,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals Color[] colorTable = new Color[this.logicalScreenDescriptor.GlobalColorTableSize]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(globalColorTableSpan); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); this.gifMetadata.GlobalColorTable = colorTable; } diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3eabbdef0c..4178d28209 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1240,10 +1240,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals Color[] colorTable = new Color[palette.Length / Unsafe.SizeOf()]; ReadOnlySpan rgbTable = MemoryMarshal.Cast(palette); - for (int i = 0; i < colorTable.Length; i++) - { - colorTable[i] = new Color(rgbTable[i]); - } + Color.FromPixel(rgbTable, colorTable); if (alpha.Length > 0) { @@ -1276,14 +1273,14 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ushort gc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(2, 2)); ushort bc = BinaryPrimitives.ReadUInt16LittleEndian(alpha.Slice(4, 2)); - pngMetadata.TransparentColor = new(new Rgb48(rc, gc, bc)); + pngMetadata.TransparentColor = Color.FromPixel(new Rgb48(rc, gc, bc)); return; } byte r = ReadByteLittleEndian(alpha, 0); byte g = ReadByteLittleEndian(alpha, 2); byte b = ReadByteLittleEndian(alpha, 4); - pngMetadata.TransparentColor = new(new Rgb24(r, g, b)); + pngMetadata.TransparentColor = Color.FromPixel(new Rgb24(r, g, b)); } } else if (this.pngColorType == PngColorType.Grayscale) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index e348d74679..8bf8be2adc 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -329,7 +329,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { // TODO: We should be able to speed this up with SIMD and masking. Rgba32 rgba32 = default; - Rgba32 transparent = Color.Transparent; + Rgba32 transparent = Color.Transparent.ToPixel(); for (int y = 0; y < accessor.Height; y++) { Span span = accessor.GetRowSpan(y); @@ -1066,7 +1066,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable else { alpha.Clear(); - Rgb24 rgb = pngMetadata.TransparentColor.Value.ToRgb24(); + Rgb24 rgb = pngMetadata.TransparentColor.Value.ToPixel(); alpha[1] = rgb.R; alpha[3] = rgb.G; alpha[5] = rgb.B; diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index f217515e3c..39b3fff27a 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -202,7 +202,7 @@ internal static class PngScanlineProcessor for (nuint x = pixelOffset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); - pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToRgba32()); + pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel()); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs index a8a70f7272..89d1b9d20e 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs @@ -22,8 +22,8 @@ internal class BlackIsZero1TiffColor : TiffBaseColorDecoder TPixel colorBlack = default; TPixel colorWhite = default; - colorBlack.FromRgba32(Color.Black); - colorWhite.FromRgba32(Color.White); + colorBlack.FromRgba32(Color.Black.ToPixel()); + colorWhite.FromRgba32(Color.White.ToPixel()); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs index c5b662979e..4cba8f2d72 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs @@ -21,8 +21,8 @@ internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder var colorBlack = default(TPixel); var colorWhite = default(TPixel); - colorBlack.FromRgba32(Color.Black); - colorWhite.FromRgba32(Color.White); + colorBlack.FromRgba32(Color.Black.ToPixel()); + colorWhite.FromRgba32(Color.White.ToPixel()); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 9ffda0f51f..c98be1fcd8 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -6,6 +6,7 @@ using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; using SixLabors.ImageSharp.Metadata.Profiles.Xmp; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Formats.Webp.BitWriter; @@ -157,7 +158,7 @@ internal abstract class BitWriterBase /// The number of times to loop the animation. If it is 0, this means infinitely. public static void WriteAnimationParameter(Stream stream, Color background, ushort loopCount) { - WebpAnimationParameter chunk = new(background.ToBgra32().PackedValue, loopCount); + WebpAnimationParameter chunk = new(background.ToPixel().PackedValue, loopCount); chunk.WriteTo(stream); } diff --git a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs index 65f1a4da46..70372fe985 100644 --- a/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs +++ b/src/ImageSharp/Formats/Webp/WebpAnimationDecoder.cs @@ -102,7 +102,7 @@ internal class WebpAnimationDecoder : IDisposable { case WebpChunkType.FrameData: Color backgroundColor = this.backgroundColorHandling == BackgroundColorHandling.Ignore - ? new Color(new Bgra32(0, 0, 0, 0)) + ? Color.FromPixel(new Bgra32(0, 0, 0, 0)) : features.AnimationBackgroundColor!.Value; uint dataSize = this.ReadFrame(stream, ref image, ref previousFrame, width, height, backgroundColor); remainingBytes -= (int)dataSize; diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 69a0afcd9b..2991f355ff 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -438,7 +438,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable byte green = (byte)stream.ReadByte(); byte red = (byte)stream.ReadByte(); byte alpha = (byte)stream.ReadByte(); - features.AnimationBackgroundColor = new Color(new Rgba32(red, green, blue, alpha)); + features.AnimationBackgroundColor = Color.FromPixel(new Rgba32(red, green, blue, alpha)); int bytesRead = stream.Read(buffer, 0, 2); if (bytesRead != 2) { diff --git a/src/ImageSharp/ImageInfo.cs b/src/ImageSharp/ImageInfo.cs index 00319e9b55..c0d1f27ca4 100644 --- a/src/ImageSharp/ImageInfo.cs +++ b/src/ImageSharp/ImageInfo.cs @@ -1,8 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; diff --git a/src/ImageSharp/Image{TPixel}.cs b/src/ImageSharp/Image{TPixel}.cs index 38f0b94d62..e12631cbd7 100644 --- a/src/ImageSharp/Image{TPixel}.cs +++ b/src/ImageSharp/Image{TPixel}.cs @@ -4,7 +4,6 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Advanced; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index adbf688612..b28911a904 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/PixelComponentInfo.cs b/src/ImageSharp/PixelFormats/PixelComponentInfo.cs new file mode 100644 index 0000000000..a761054144 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelComponentInfo.cs @@ -0,0 +1,111 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Represents pixel component information within a pixel format. +/// +public readonly struct PixelComponentInfo +{ + private readonly long precisionData1; + private readonly long precisionData2; + + private PixelComponentInfo(int count, int padding, long precisionData1, long precisionData2) + { + this.ComponentCount = count; + this.Padding = padding; + this.precisionData1 = precisionData1; + this.precisionData2 = precisionData2; + } + + /// + /// Gets the number of components within the pixel. + /// + public int ComponentCount { get; } + + /// + /// Gets the number of bytes of padding within the pixel. + /// + public int Padding { get; } + + /// + /// Creates a new instance. + /// + /// The type of pixel format. + /// The number of components within the pixel format. + /// The precision in bits of each component. + /// The . + /// The component precision and index cannot exceed the component range. + public static PixelComponentInfo Create(int count, params int[] precision) + where TPixel : unmanaged, IPixel + { + if (precision.Length != count || precision.Length > 16) + { + throw new ArgumentException($"Count must match the length of precision array and cannot exceed 16."); + } + + long precisionData1 = 0; + long precisionData2 = 0; + int sum = 0; + for (int i = 0; i < precision.Length; i++) + { + int p = precision[i]; + if (p is < 0 or > 255) + { + throw new ArgumentException("Precision must be between 0 and 255."); + } + + if (i < 8) + { + precisionData1 |= ((long)p) << (8 * i); + } + else + { + precisionData2 |= ((long)p) << (8 * (i - 8)); + } + + sum += p; + } + + return new PixelComponentInfo(count, (Unsafe.SizeOf() * 8) - sum, precisionData1, precisionData2); + } + + /// + /// Returns the precision of the component in bits at the given index. + /// + /// The component index. + /// The . + /// The component index cannot exceed the component range. + public int GetComponentPrecision(int componentIndex) + { + if (componentIndex < 0 || componentIndex >= this.ComponentCount) + { + throw new ArgumentOutOfRangeException($"Component index must be between 0 and {this.ComponentCount - 1} inclusive."); + } + + long selectedPrecisionData = componentIndex < 8 ? this.precisionData1 : this.precisionData2; + return (int)((selectedPrecisionData >> (8 * (componentIndex & 7))) & 0xFF); + } + + /// + /// Returns the maximum precision in bits of all components. + /// + /// The . + public int GetMaximumComponentPrecision() + { + int maxPrecision = 0; + for (int i = 0; i < this.ComponentCount; i++) + { + int componentPrecision = this.GetComponentPrecision(i); + if (componentPrecision > maxPrecision) + { + maxPrecision = componentPrecision; + } + } + + return maxPrecision; + } +} diff --git a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs index 3480ac76ed..2f15b7fad8 100644 --- a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs +++ b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs @@ -4,47 +4,67 @@ namespace SixLabors.ImageSharp.PixelFormats; /// -/// Provides enumeration of the precision of individual components within a pixel format. +/// Provides enumeration of the precision in bits of individual components within a pixel format. /// public enum PixelComponentPrecision { /// /// 8-bit signed integer. /// - SByte, + SByte = sizeof(sbyte) * 8, /// /// 8-bit unsigned integer. /// - Byte, + Byte = sizeof(byte) * 8, /// /// 16-bit signed integer. /// - Short, + Short = sizeof(short) * 8, /// /// 16-bit unsigned integer. /// - UShort, + UShort = sizeof(ushort) * 8, /// /// 32-bit signed integer. /// - Int, + Int = sizeof(int) * 8, /// /// 32-bit unsigned integer. /// - UInt, + UInt = sizeof(uint) * 8, + + /// + /// 64-bit signed integer. + /// + Long = sizeof(long) * 8, + + /// + /// 64-bit unsigned integer. + /// + ULong = sizeof(ulong) * 8, /// /// 16-bit floating point. /// - Half, + Half = (sizeof(float) * 8) / 2, /// /// 32-bit floating point. /// - Float + Float = sizeof(float) * 8, + + /// + /// 64-bit floating point. + /// + Double = sizeof(double) * 8, + + /// + /// 128-bit floating point. + /// + Decimal = sizeof(decimal) * 8, } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 33fa62d1af..abae4f246f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -57,7 +56,7 @@ public partial struct A8 : IPixel, IPackedVector public static bool operator !=(A8 left, A8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 66523f0408..e1399f05c0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -146,22 +145,6 @@ public partial struct Abgr32 : IPixel, IPackedVector set => this.Abgr = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Abgr32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Abgr32(Color color) => color.ToAbgr32(); - /// /// Compares two objects for equality. /// @@ -185,7 +168,7 @@ public partial struct Abgr32 : IPixel, IPackedVector public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index d3375f65f6..2b7bcf9133 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -146,22 +145,6 @@ public partial struct Argb32 : IPixel, IPackedVector set => this.Argb = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Argb32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Argb32(Color color) => color.ToArgb32(); - /// /// Compares two objects for equality. /// @@ -185,7 +168,7 @@ public partial struct Argb32 : IPixel, IPackedVector public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 9d0186c835..c9c3246807 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -50,22 +49,6 @@ public partial struct Bgr24 : IPixel this.B = b; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Bgr24 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Bgr24(Color color) => color.ToBgr24(); - /// /// Compares two objects for equality. /// @@ -89,7 +72,7 @@ public partial struct Bgr24 : IPixel public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 8, 8, 8), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 6135ab3e7e..d020cf0256 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -61,7 +60,7 @@ public partial struct Bgr565 : IPixel, IPackedVector public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 5, 6, 5), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index 7da4fad4f5..b3a96523ee 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -99,22 +98,6 @@ public partial struct Bgra32 : IPixel, IPackedVector set => this.Bgra = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Bgra32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Bgra32(Color color) => color.ToBgra32(); - /// /// Compares two objects for equality. /// @@ -138,7 +121,7 @@ public partial struct Bgra32 : IPixel, IPackedVector public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index effc0d6e5d..510d6666f7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -59,7 +58,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 4, 4, 4, 4), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 14110b1d10..68dbd9544e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -62,7 +61,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 5, 5, 5, 1), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index f9a36305d7..fbe7a0c52f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -62,7 +61,7 @@ public partial struct Byte4 : IPixel, IPackedVector public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 7e1997251e..aca64ae7a0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -47,7 +46,7 @@ public partial struct HalfSingle : IPixel, IPackedVector public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Half, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 16), PixelAlphaRepresentation.None); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 1e3854feb7..5a25d523bb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -54,7 +53,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Half, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 2331605794..7ad7b07f40 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -59,7 +58,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Half, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index fa07d650bc..0c58fb1fda 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -49,7 +48,7 @@ public partial struct L16 : IPixel, IPackedVector public static bool operator !=(L16 left, L16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 28fb7ec720..2cd8b20e77 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -50,7 +49,7 @@ public partial struct L8 : IPixel, IPackedVector public static bool operator !=(L8 left, L8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(1, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 8), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 99203518af..b811df4b4d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -73,7 +72,7 @@ public partial struct La16 : IPixel, IPackedVector public static bool operator !=(La16 left, La16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index a8c0dcd940..e6a63f5ec1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -75,7 +74,7 @@ public partial struct La32 : IPixel, IPackedVector public static bool operator !=(La32 left, La32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 5db53e8539..f7427e65ce 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -62,7 +61,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.SByte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 4c850e4269..beeae655a0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -64,7 +63,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.SByte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 7fd299d6db..8152c89d37 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -63,7 +62,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Short, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index ff5cd6a987..3f37cb80f7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -65,7 +64,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Short, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 9a27533414..594bdd9a13 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -59,7 +58,7 @@ public partial struct Rg32 : IPixel, IPackedVector public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index f4c907abf0..8d0c7cd48c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -53,22 +52,6 @@ public partial struct Rgb24 : IPixel this.B = b; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgb24 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb24(Color color) => color.ToRgb24(); - /// /// Allows the implicit conversion of an instance of to a /// . @@ -108,7 +91,7 @@ public partial struct Rgb24 : IPixel public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 8, 8, 8), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index 642883ff02..f7aac32f42 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -71,7 +70,7 @@ public partial struct Rgb48 : IPixel public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(3, PixelComponentPrecision.UShort, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 16, 16, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 5f289577fe..84482a7aaa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -62,7 +61,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 10, 10, 10, 2), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index f775e8ae11..f391e64740 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -6,7 +6,6 @@ using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -175,22 +174,6 @@ public partial struct Rgba32 : IPixel, IPackedVector set => this.Rgba = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgba32 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba32(Color color) => color.ToRgba32(); - /// /// Allows the implicit conversion of an instance of to a /// . @@ -288,7 +271,7 @@ public partial struct Rgba32 : IPixel, IPackedVector } /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Byte, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 84860d66d8..47062779ba 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -4,7 +4,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -169,22 +168,6 @@ public partial struct Rgba64 : IPixel, IPackedVector set => Unsafe.As(ref this) = value; } - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Color(Rgba64 source) => new(source); - - /// - /// Converts a to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba64(Color color) => color.ToPixel(); - /// /// Compares two objects for equality. /// @@ -208,7 +191,7 @@ public partial struct Rgba64 : IPixel, IPackedVector public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.UShort, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 064064f737..ce1c6d5729 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -5,7 +5,6 @@ using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -98,7 +97,7 @@ public partial struct RgbaVector : IPixel public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Float, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 32, 32, 32, 32), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 8af952b180..786c98ee46 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -66,7 +65,7 @@ public partial struct Short2 : IPixel, IPackedVector public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Short, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 4c60887df0..890e66299a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; namespace SixLabors.ImageSharp.PixelFormats; @@ -68,7 +67,7 @@ public partial struct Short4 : IPixel, IPackedVector public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(4, PixelComponentPrecision.Short, PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index cf3707f9e5..4d3f9e22d4 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -5,7 +5,6 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/Formats/PixelTypeInfo.cs b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs similarity index 65% rename from src/ImageSharp/Formats/PixelTypeInfo.cs rename to src/ImageSharp/PixelFormats/PixelTypeInfo.cs index 170ffcfae6..e209b21e12 100644 --- a/src/ImageSharp/Formats/PixelTypeInfo.cs +++ b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs @@ -2,12 +2,11 @@ // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; // TODO: Review this type as it's used to represent 2 different things. // 1.The encoded image pixel format. // 2. The pixel format of the decoded image. -namespace SixLabors.ImageSharp.Formats; +namespace SixLabors.ImageSharp.PixelFormats; /// /// Contains information about the pixels that make up an images visual data. @@ -23,15 +22,10 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) /// public int BitsPerPixel { get; init; } = bitsPerPixel; - /// - /// Gets the count of the color components - /// - public int ComponentCount { get; init; } - /// /// Gets the maximum precision of components within the pixel. /// - public PixelComponentPrecision? MaxComponentPrecision { get; init; } + public PixelComponentInfo? ComponentInfo { get; init; } /// /// Gets the pixel alpha transparency behavior. @@ -39,16 +33,21 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) /// public PixelAlphaRepresentation? AlphaRepresentation { get; init; } - internal static PixelTypeInfo Create( - byte componentCount, - PixelComponentPrecision componentPrecision, - PixelAlphaRepresentation pixelAlphaRepresentation) + /// + /// Creates a new instance. + /// + /// The type of pixel format. + /// The pixel component info. + /// The pixel alpha representation. + /// The . + public static PixelTypeInfo Create( + PixelComponentInfo info, + PixelAlphaRepresentation alphaRepresentation) where TPixel : unmanaged, IPixel => new() { BitsPerPixel = Unsafe.SizeOf() * 8, - ComponentCount = componentCount, - MaxComponentPrecision = componentPrecision, - AlphaRepresentation = pixelAlphaRepresentation + ComponentInfo = info, + AlphaRepresentation = alphaRepresentation }; } diff --git a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs index 4a02642fd6..c8a381d590 100644 --- a/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/LomographProcessor{TPixel}.cs @@ -12,7 +12,7 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters; internal class LomographProcessor : FilterProcessor where TPixel : unmanaged, IPixel { - private static readonly Color VeryDarkGreen = Color.FromRgba(0, 10, 0, 255); + private static readonly Color VeryDarkGreen = Color.FromPixel(new Rgba32(0, 10, 0, 255)); private readonly LomographProcessor definition; /// diff --git a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs index c1b79d10a1..84c0364faf 100644 --- a/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Filters/PolaroidProcessor{TPixel}.cs @@ -12,8 +12,8 @@ namespace SixLabors.ImageSharp.Processing.Processors.Filters; internal class PolaroidProcessor : FilterProcessor where TPixel : unmanaged, IPixel { - private static readonly Color LightOrange = Color.FromRgba(255, 153, 102, 128); - private static readonly Color VeryDarkOrange = Color.FromRgb(102, 34, 0); + private static readonly Color LightOrange = Color.FromPixel(new Rgba32(255, 153, 102, 128)); + private static readonly Color VeryDarkOrange = Color.FromPixel(new Rgb24(102, 34, 0)); private readonly PolaroidProcessor definition; /// diff --git a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs index a6aac20c3b..5ba7809e13 100644 --- a/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/GetSetPixel.cs @@ -21,7 +21,7 @@ public class GetSetPixel public Rgba32 GetSetImageSharp() { using Image image = new(400, 400); - image[200, 200] = Color.White; + image[200, 200] = Color.White.ToPixel(); return image[200, 200]; } } diff --git a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs index 58c23d2fe7..82fce7dad7 100644 --- a/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/BokehBlur.cs @@ -13,7 +13,7 @@ public class BokehBlur [Benchmark] public void Blur() { - using Image image = new(Configuration.Default, 400, 400, Color.White); + using Image image = new(Configuration.Default, 400, 400, Color.White.ToPixel()); image.Mutate(c => c.BokehBlur()); } } diff --git a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs index bf760aa2d9..fae80fe841 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Diffuse.cs @@ -13,7 +13,7 @@ public class Diffuse [Benchmark] public Size DoDiffuse() { - using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Dither(KnownDitherings.FloydSteinberg)); return image.Size; @@ -22,7 +22,7 @@ public class Diffuse [Benchmark] public Size DoDither() { - using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 800, 800, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Dither()); return image.Size; diff --git a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs index 160df21e62..462d83488d 100644 --- a/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs +++ b/tests/ImageSharp.Benchmarks/Processing/GaussianBlur.cs @@ -13,7 +13,7 @@ public class GaussianBlur [Benchmark] public void Blur() { - using var image = new Image(Configuration.Default, 400, 400, Color.White); + using Image image = new(Configuration.Default, 400, 400, Color.White.ToPixel()); image.Mutate(c => c.GaussianBlur()); } } diff --git a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs index 89d2966d7c..b041a9d57e 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Rotate.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Rotate.cs @@ -13,7 +13,7 @@ public class Rotate [Benchmark] public Size DoRotate() { - using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Rotate(37.5F)); return image.Size; diff --git a/tests/ImageSharp.Benchmarks/Processing/Skew.cs b/tests/ImageSharp.Benchmarks/Processing/Skew.cs index baeff29a85..9f0103fa6b 100644 --- a/tests/ImageSharp.Benchmarks/Processing/Skew.cs +++ b/tests/ImageSharp.Benchmarks/Processing/Skew.cs @@ -13,7 +13,7 @@ public class Skew [Benchmark] public Size DoSkew() { - using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond); + using Image image = new(Configuration.Default, 400, 400, Color.BlanchedAlmond.ToPixel()); image.Mutate(x => x.Skew(20, 10)); return image.Size; diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs index 4091e0cd40..2eb821b61d 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastFrom.cs @@ -12,10 +12,10 @@ public partial class ColorTests [Fact] public void Rgba64() { - var source = new Rgba64(100, 2222, 3333, 4444); + Rgba64 source = new(100, 2222, 3333, 4444); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgba64 data = color.ToPixel(); @@ -25,10 +25,10 @@ public partial class ColorTests [Fact] public void Rgba32() { - var source = new Rgba32(1, 22, 33, 231); + Rgba32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgba32 data = color.ToPixel(); @@ -38,10 +38,10 @@ public partial class ColorTests [Fact] public void Argb32() { - var source = new Argb32(1, 22, 33, 231); + Argb32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Argb32 data = color.ToPixel(); @@ -51,10 +51,10 @@ public partial class ColorTests [Fact] public void Bgra32() { - var source = new Bgra32(1, 22, 33, 231); + Bgra32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Bgra32 data = color.ToPixel(); @@ -64,10 +64,10 @@ public partial class ColorTests [Fact] public void Abgr32() { - var source = new Abgr32(1, 22, 33, 231); + Abgr32 source = new(1, 22, 33, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Abgr32 data = color.ToPixel(); @@ -77,10 +77,10 @@ public partial class ColorTests [Fact] public void Rgb24() { - var source = new Rgb24(1, 22, 231); + Rgb24 source = new(1, 22, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Rgb24 data = color.ToPixel(); @@ -90,10 +90,10 @@ public partial class ColorTests [Fact] public void Bgr24() { - var source = new Bgr24(1, 22, 231); + Bgr24 source = new(1, 22, 231); // Act: - Color color = source; + Color color = Color.FromPixel(source); // Assert: Bgr24 data = color.ToPixel(); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs index dacec71449..14a5a44f18 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -16,10 +16,10 @@ public partial class ColorTests var source = new Rgba64(100, 2222, 3333, 4444); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgba64 data = color; + Rgba64 data = color.ToPixel(); Assert.Equal(source, data); } @@ -29,10 +29,10 @@ public partial class ColorTests var source = new Rgba32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgba32 data = color; + Rgba32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -42,10 +42,10 @@ public partial class ColorTests var source = new Argb32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Argb32 data = color; + Argb32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -55,10 +55,10 @@ public partial class ColorTests var source = new Bgra32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Bgra32 data = color; + Bgra32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -68,10 +68,10 @@ public partial class ColorTests var source = new Abgr32(1, 22, 33, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Abgr32 data = color; + Abgr32 data = color.ToPixel(); Assert.Equal(source, data); } @@ -81,10 +81,10 @@ public partial class ColorTests var source = new Rgb24(1, 22, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Rgb24 data = color; + Rgb24 data = color.ToPixel(); Assert.Equal(source, data); } @@ -94,10 +94,10 @@ public partial class ColorTests var source = new Bgr24(1, 22, 231); // Act: - var color = new Color(source); + var color = Color.FromPixel(source); // Assert: - Bgr24 data = color; + Bgr24 data = color.ToPixel(); Assert.Equal(source, data); } @@ -105,7 +105,7 @@ public partial class ColorTests public void Vector4Constructor() { // Act: - Color color = new(Vector4.One); + Color color = (Color)Vector4.One; // Assert: Assert.Equal(new RgbaVector(1, 1, 1, 1), color.ToPixel()); @@ -117,7 +117,7 @@ public partial class ColorTests [Fact] public void GenericPixelRoundTrip() { - AssertGenericPixelRoundTrip(new RgbaVector(float.Epsilon, 2 * float.Epsilon, float.MaxValue, float.MinValue)); + AssertGenericPixelRoundTrip(new RgbaVector(0.5f, 0.75f, 1, 0)); AssertGenericPixelRoundTrip(new Rgba64(1, 2, ushort.MaxValue, ushort.MaxValue - 1)); AssertGenericPixelRoundTrip(new Rgb48(1, 2, ushort.MaxValue - 1)); AssertGenericPixelRoundTrip(new La32(1, ushort.MaxValue - 1)); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs index 3ea8623d94..9126543e55 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.ConstructFrom.cs @@ -12,10 +12,10 @@ public partial class ColorTests [Fact] public void Rgba64() { - var source = new Rgba64(100, 2222, 3333, 4444); + Rgba64 source = new(100, 2222, 3333, 4444); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgba64 data = color.ToPixel(); @@ -25,10 +25,10 @@ public partial class ColorTests [Fact] public void Rgba32() { - var source = new Rgba32(1, 22, 33, 231); + Rgba32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgba32 data = color.ToPixel(); @@ -38,10 +38,10 @@ public partial class ColorTests [Fact] public void Argb32() { - var source = new Argb32(1, 22, 33, 231); + Argb32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Argb32 data = color.ToPixel(); @@ -51,10 +51,10 @@ public partial class ColorTests [Fact] public void Bgra32() { - var source = new Bgra32(1, 22, 33, 231); + Bgra32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Bgra32 data = color.ToPixel(); @@ -64,10 +64,10 @@ public partial class ColorTests [Fact] public void Abgr32() { - var source = new Abgr32(1, 22, 33, 231); + Abgr32 source = new(1, 22, 33, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Abgr32 data = color.ToPixel(); @@ -77,10 +77,10 @@ public partial class ColorTests [Fact] public void Rgb24() { - var source = new Rgb24(1, 22, 231); + Rgb24 source = new(1, 22, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Rgb24 data = color.ToPixel(); @@ -90,10 +90,10 @@ public partial class ColorTests [Fact] public void Bgr24() { - var source = new Bgr24(1, 22, 231); + Bgr24 source = new(1, 22, 231); // Act: - var color = new Color(source); + Color color = Color.FromPixel(source); // Assert: Bgr24 data = color.ToPixel(); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.cs b/tests/ImageSharp.Tests/Color/ColorTests.cs index f7e2092176..d430df5b44 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.cs @@ -10,12 +10,12 @@ public partial class ColorTests [Fact] public void WithAlpha() { - var c1 = Color.FromRgba(111, 222, 55, 255); + Color c1 = Color.FromPixel(new Rgba32(111, 222, 55, 255)); Color c2 = c1.WithAlpha(0.5f); - var expected = new Rgba32(111, 222, 55, 128); + Rgba32 expected = new(111, 222, 55, 128); - Assert.Equal(expected, (Rgba32)c2); + Assert.Equal(expected, c2.ToPixel()); } [Theory] @@ -23,13 +23,13 @@ public partial class ColorTests [InlineData(true)] public void Equality_WhenTrue(bool highPrecision) { - Color c1 = new Rgba64(100, 2000, 3000, 40000); - Color c2 = new Rgba64(100, 2000, 3000, 40000); + Color c1 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); + Color c2 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); if (highPrecision) { - c1 = Color.FromPixel(c1.ToPixel()); - c2 = Color.FromPixel(c2.ToPixel()); + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); } Assert.True(c1.Equals(c2)); @@ -43,15 +43,15 @@ public partial class ColorTests [InlineData(true)] public void Equality_WhenFalse(bool highPrecision) { - Color c1 = new Rgba64(100, 2000, 3000, 40000); - Color c2 = new Rgba64(101, 2000, 3000, 40000); - Color c3 = new Rgba64(100, 2000, 3000, 40001); + Color c1 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40000)); + Color c2 = Color.FromPixel(new Rgba64(101, 2000, 3000, 40000)); + Color c3 = Color.FromPixel(new Rgba64(100, 2000, 3000, 40001)); if (highPrecision) { - c1 = Color.FromPixel(c1.ToPixel()); - c2 = Color.FromPixel(c2.ToPixel()); - c3 = Color.FromPixel(c3.ToPixel()); + c1 = Color.FromPixel(c1.ToPixel()); + c2 = Color.FromPixel(c2.ToPixel()); + c3 = Color.FromPixel(c3.ToPixel()); } Assert.False(c1.Equals(c2)); @@ -74,7 +74,7 @@ public partial class ColorTests if (highPrecision) { - color = Color.FromPixel(color.ToPixel()); + color = Color.FromPixel(color.ToPixel()); } string actual = color.ToHex(); @@ -84,22 +84,22 @@ public partial class ColorTests [Fact] public void WebSafePalette_IsCorrect() { - Rgba32[] actualPalette = Color.WebSafePalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Rgba32[] actualPalette = Color.WebSafePalette.ToArray().Select(c => c.ToPixel()).ToArray(); for (int i = 0; i < ReferencePalette.WebSafeColors.Length; i++) { - Assert.Equal((Rgba32)ReferencePalette.WebSafeColors[i], actualPalette[i]); + Assert.Equal(ReferencePalette.WebSafeColors[i].ToPixel(), actualPalette[i]); } } [Fact] public void WernerPalette_IsCorrect() { - Rgba32[] actualPalette = Color.WernerPalette.ToArray().Select(c => (Rgba32)c).ToArray(); + Rgba32[] actualPalette = Color.WernerPalette.ToArray().Select(c => c.ToPixel()).ToArray(); for (int i = 0; i < ReferencePalette.WernerColors.Length; i++) { - Assert.Equal((Rgba32)ReferencePalette.WernerColors[i], actualPalette[i]); + Assert.Equal(ReferencePalette.WernerColors[i].ToPixel(), actualPalette[i]); } } @@ -108,66 +108,48 @@ public partial class ColorTests [Fact] public void ShortHex() { - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)Color.ParseHex("#fff")); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)Color.ParseHex("fff")); - Assert.Equal(new Rgba32(0, 0, 0, 255), (Rgba32)Color.ParseHex("000f")); + Assert.Equal(new Rgb24(255, 255, 255), Color.ParseHex("#fff").ToPixel()); + Assert.Equal(new Rgb24(255, 255, 255), Color.ParseHex("fff").ToPixel()); + Assert.Equal(new Rgba32(0, 0, 0, 255), Color.ParseHex("000f").ToPixel()); } [Fact] public void TryShortHex() { Assert.True(Color.TryParseHex("#fff", out Color actual)); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)actual); + Assert.Equal(new Rgb24(255, 255, 255), actual.ToPixel()); Assert.True(Color.TryParseHex("fff", out actual)); - Assert.Equal(new Rgb24(255, 255, 255), (Rgb24)actual); + Assert.Equal(new Rgb24(255, 255, 255), actual.ToPixel()); Assert.True(Color.TryParseHex("000f", out actual)); - Assert.Equal(new Rgba32(0, 0, 0, 255), (Rgba32)actual); + Assert.Equal(new Rgba32(0, 0, 0, 255), actual.ToPixel()); } [Fact] public void LeadingPoundIsOptional() { - Assert.Equal(new Rgb24(0, 128, 128), (Rgb24)Color.ParseHex("#008080")); - Assert.Equal(new Rgb24(0, 128, 128), (Rgb24)Color.ParseHex("008080")); + Assert.Equal(new Rgb24(0, 128, 128), Color.ParseHex("#008080").ToPixel()); + Assert.Equal(new Rgb24(0, 128, 128), Color.ParseHex("008080").ToPixel()); } [Fact] - public void ThrowsOnEmpty() - { - Assert.Throws(() => Color.ParseHex(string.Empty)); - } + public void ThrowsOnEmpty() => Assert.Throws(() => Color.ParseHex(string.Empty)); [Fact] - public void ThrowsOnInvalid() - { - Assert.Throws(() => Color.ParseHex("!")); - } + public void ThrowsOnInvalid() => Assert.Throws(() => Color.ParseHex("!")); [Fact] - public void ThrowsOnNull() - { - Assert.Throws(() => Color.ParseHex(null)); - } + public void ThrowsOnNull() => Assert.Throws(() => Color.ParseHex(null)); [Fact] - public void FalseOnEmpty() - { - Assert.False(Color.TryParseHex(string.Empty, out Color _)); - } + public void FalseOnEmpty() => Assert.False(Color.TryParseHex(string.Empty, out Color _)); [Fact] - public void FalseOnInvalid() - { - Assert.False(Color.TryParseHex("!", out Color _)); - } + public void FalseOnInvalid() => Assert.False(Color.TryParseHex("!", out Color _)); [Fact] - public void FalseOnNull() - { - Assert.False(Color.TryParseHex(null, out Color _)); - } + public void FalseOnNull() => Assert.False(Color.TryParseHex(null, out Color _)); } public class FromString @@ -177,10 +159,10 @@ public partial class ColorTests { foreach (string name in ReferencePalette.ColorNames.Keys) { - Rgba32 expected = ReferencePalette.ColorNames[name]; - Assert.Equal(expected, (Rgba32)Color.Parse(name)); - Assert.Equal(expected, (Rgba32)Color.Parse(name.ToLowerInvariant())); - Assert.Equal(expected, (Rgba32)Color.Parse(expected.ToHex())); + Rgba32 expected = ReferencePalette.ColorNames[name].ToPixel(); + Assert.Equal(expected, Color.Parse(name).ToPixel()); + Assert.Equal(expected, Color.Parse(name.ToLowerInvariant()).ToPixel()); + Assert.Equal(expected, Color.Parse(expected.ToHex()).ToPixel()); } } @@ -189,53 +171,35 @@ public partial class ColorTests { foreach (string name in ReferencePalette.ColorNames.Keys) { - Rgba32 expected = ReferencePalette.ColorNames[name]; + Rgba32 expected = ReferencePalette.ColorNames[name].ToPixel(); Assert.True(Color.TryParse(name, out Color actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); Assert.True(Color.TryParse(name.ToLowerInvariant(), out actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); Assert.True(Color.TryParse(expected.ToHex(), out actual)); - Assert.Equal(expected, (Rgba32)actual); + Assert.Equal(expected, actual.ToPixel()); } } [Fact] - public void ThrowsOnEmpty() - { - Assert.Throws(() => Color.Parse(string.Empty)); - } + public void ThrowsOnEmpty() => Assert.Throws(() => Color.Parse(string.Empty)); [Fact] - public void ThrowsOnInvalid() - { - Assert.Throws(() => Color.Parse("!")); - } + public void ThrowsOnInvalid() => Assert.Throws(() => Color.Parse("!")); [Fact] - public void ThrowsOnNull() - { - Assert.Throws(() => Color.Parse(null)); - } + public void ThrowsOnNull() => Assert.Throws(() => Color.Parse(null)); [Fact] - public void FalseOnEmpty() - { - Assert.False(Color.TryParse(string.Empty, out Color _)); - } + public void FalseOnEmpty() => Assert.False(Color.TryParse(string.Empty, out Color _)); [Fact] - public void FalseOnInvalid() - { - Assert.False(Color.TryParse("!", out Color _)); - } + public void FalseOnInvalid() => Assert.False(Color.TryParse("!", out Color _)); [Fact] - public void FalseOnNull() - { - Assert.False(Color.TryParse(null, out Color _)); - } + public void FalseOnNull() => Assert.False(Color.TryParse(null, out Color _)); } } diff --git a/tests/ImageSharp.Tests/Color/RgbaDouble.cs b/tests/ImageSharp.Tests/Color/RgbaDouble.cs new file mode 100644 index 0000000000..476ff03365 --- /dev/null +++ b/tests/ImageSharp.Tests/Color/RgbaDouble.cs @@ -0,0 +1,180 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Tests; + +/// +/// Unpacked pixel type containing four 64-bit floating-point values typically ranging from 0 to 1. +/// The color components are stored in red, green, blue, and alpha order. +/// +/// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. +/// +/// +/// +/// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, +/// as it avoids the need to create new values for modification operations. +/// +/// +/// Initializes a new instance of the struct. +/// +/// The red component. +/// The green component. +/// The blue component. +/// The alpha component. +[StructLayout(LayoutKind.Sequential)] +[method: MethodImpl(InliningOptions.ShortMethod)] +public partial struct RgbaDouble(double r, double g, double b, double a = 1) : IPixel +{ + /// + /// Gets or sets the red component. + /// + public double R = r; + + /// + /// Gets or sets the green component. + /// + public double G = g; + + /// + /// Gets or sets the blue component. + /// + public double B = b; + + /// + /// Gets or sets the alpha component. + /// + public double A = a; + + private const float MaxBytes = byte.MaxValue; + private static readonly Vector4 Max = new(MaxBytes); + private static readonly Vector4 Half = new(0.5F); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator ==(RgbaDouble left, RgbaDouble right) => left.Equals(right); + + /// + /// Compares two objects for equality. + /// + /// The on the left side of the operand. + /// The on the right side of the operand. + /// + /// True if the parameter is not equal to the parameter; otherwise, false. + /// + [MethodImpl(InliningOptions.ShortMethod)] + public static bool operator !=(RgbaDouble left, RgbaDouble right) => !left.Equals(right); + + /// + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 64, 64, 64, 64), PixelAlphaRepresentation.Unassociated); + + /// + public readonly PixelOperations CreatePixelOperations() => new(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromVector4(Vector4 vector) + { + vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); + this.R = vector.X; + this.G = vector.Y; + this.B = vector.Z; + this.A = vector.W; + } + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly Vector4 ToVector4() => new((float)this.R, (float)this.G, (float)this.B, (float)this.A); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + + /// + public override readonly bool Equals(object obj) => obj is RgbaDouble other && this.Equals(other); + + /// + [MethodImpl(InliningOptions.ShortMethod)] + public readonly bool Equals(RgbaDouble other) => + this.R.Equals(other.R) + && this.G.Equals(other.G) + && this.B.Equals(other.B) + && this.A.Equals(other.A); + + /// + public override readonly string ToString() => FormattableString.Invariant($"RgbaDouble({this.R:#0.##}, {this.G:#0.##}, {this.B:#0.##}, {this.A:#0.##})"); + + /// + public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B, this.A); +} diff --git a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs index 533f0c6dee..88f4cde7ac 100644 --- a/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs +++ b/tests/ImageSharp.Tests/Drawing/DrawImageTests.cs @@ -119,7 +119,7 @@ public class DrawImageTests public void WorksWithDifferentLocations(TestImageProvider provider, int x, int y) { using Image background = provider.GetImage(); - using Image overlay = new(50, 50, Color.Black.ToRgba32()); + using Image overlay = new(50, 50, Color.Black.ToPixel()); background.Mutate(c => c.DrawImage(overlay, new Point(x, y), PixelColorBlendingMode.Normal, 1F)); @@ -144,7 +144,7 @@ public class DrawImageTests public void WorksWithDifferentBounds(TestImageProvider provider, int width, int height) { using Image background = provider.GetImage(); - using Image overlay = new(50, 50, Color.Black.ToRgba32()); + using Image overlay = new(50, 50, Color.Black.ToPixel()); background.Mutate(c => c.DrawImage(overlay, new Rectangle(0, 0, width, height), PixelColorBlendingMode.Normal, 1F)); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index bc277bf485..800b1fb4bc 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -581,7 +581,7 @@ public partial class PngDecoderTests using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata metadata = image.Metadata.GetPngMetadata(); Assert.NotNull(metadata.ColorTable); - Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToPixel().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/2209 @@ -594,7 +594,7 @@ public partial class PngDecoderTests ImageInfo imageInfo = Image.Identify(stream); PngMetadata metadata = imageInfo.Metadata.GetPngMetadata(); Assert.NotNull(metadata.ColorTable); - Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToRgba32().A < 255); + Assert.Contains(metadata.ColorTable.Value.ToArray(), x => x.ToPixel().A < 255); } // https://github.com/SixLabors/ImageSharp/issues/410 diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index e70854b082..477d88e9a8 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -391,7 +391,7 @@ public partial class PngEncoderTests TransparentColorMode = PngTransparentColorMode.Clear, ColorType = colorType }; - Rgba32 rgba32 = Color.Blue; + Rgba32 rgba32 = Color.Blue.ToPixel(); image.ProcessPixelRows(accessor => { for (int y = 0; y < image.Height; y++) @@ -418,7 +418,7 @@ public partial class PngEncoderTests // assert memStream.Position = 0; using Image actual = Image.Load(memStream); - Rgba32 expectedColor = Color.Blue; + Rgba32 expectedColor = Color.Blue.ToPixel(); if (colorType is PngColorType.Grayscale or PngColorType.GrayscaleWithAlpha) { byte luminance = ColorNumerics.Get8BitBT709Luminance(expectedColor.R, expectedColor.G, expectedColor.B); @@ -427,13 +427,14 @@ public partial class PngEncoderTests actual.ProcessPixelRows(accessor => { + Rgba32 transparent = Color.Transparent.ToPixel(); for (int y = 0; y < accessor.Height; y++) { Span rowSpan = accessor.GetRowSpan(y); if (y > 25) { - expectedColor = Color.Transparent; + expectedColor = transparent; } for (int x = 0; x < accessor.Width; x++) diff --git a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs index b174403839..3582dc75a6 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/PhotometricInterpretation/PhotometricInterpretationTestBase.cs @@ -47,7 +47,7 @@ public abstract class PhotometricInterpretationTestBase using (var image = new Image(resultWidth, resultHeight)) { - image.Mutate(x => x.BackgroundColor(DefaultColor)); + image.Mutate(x => x.BackgroundColor(Color.FromPixel(DefaultColor))); Buffer2D pixels = image.GetRootFramePixelBuffer(); decodeAction(pixels); diff --git a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs index b74093fcc1..dce6ebc38f 100644 --- a/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tiff/TiffEncoderMultiframeTests.cs @@ -70,9 +70,9 @@ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester using Image image = provider.GetImage(); Assert.Equal(1, image.Frames.Count); - using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32()); + using var image1 = new Image(image.Width, image.Height, Color.Green.ToPixel()); - using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32()); + using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToPixel()); image.Frames.AddFrame(image1.Frames.RootFrame); image.Frames.AddFrame(image2.Frames.RootFrame); @@ -97,8 +97,8 @@ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester ImageFrame frame1 = output.Frames[1]; ImageFrame frame2 = output.Frames[2]; - Assert.Equal(Color.Green.ToRgba32(), frame1[10, 10]); - Assert.Equal(Color.Yellow.ToRgba32(), frame2[10, 10]); + Assert.Equal(Color.Green.ToPixel(), frame1[10, 10]); + Assert.Equal(Color.Yellow.ToPixel(), frame2[10, 10]); Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression); Assert.Equal(TiffCompression.Deflate, frame1.Metadata.GetTiffMetadata().Compression); @@ -122,11 +122,11 @@ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester { using Image image = provider.GetImage(); - using var image0 = new Image(image.Width, image.Height, Color.Red.ToRgba32()); + using var image0 = new Image(image.Width, image.Height, Color.Red.ToPixel()); - using var image1 = new Image(image.Width, image.Height, Color.Green.ToRgba32()); + using var image1 = new Image(image.Width, image.Height, Color.Green.ToPixel()); - using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToRgba32()); + using var image2 = new Image(image.Width, image.Height, Color.Yellow.ToPixel()); image.Frames.AddFrame(image0.Frames.RootFrame); image.Frames.AddFrame(image1.Frames.RootFrame); @@ -154,9 +154,9 @@ public class TiffEncoderMultiframeTests : TiffEncoderBaseTester ImageFrame frame1 = output.Frames[1]; ImageFrame frame2 = output.Frames[2]; - Assert.Equal(Color.Red.ToRgba32(), frame0[10, 10]); - Assert.Equal(Color.Green.ToRgba32(), frame1[10, 10]); - Assert.Equal(Color.Yellow.ToRgba32(), frame2[10, 10]); + Assert.Equal(Color.Red.ToPixel(), frame0[10, 10]); + Assert.Equal(Color.Green.ToPixel(), frame1[10, 10]); + Assert.Equal(Color.Yellow.ToPixel(), frame2[10, 10]); Assert.Equal(TiffCompression.Lzw, frame0.Metadata.GetTiffMetadata().Compression); Assert.Equal(TiffCompression.Lzw, frame1.Metadata.GetTiffMetadata().Compression); diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs index 62d1ef4db9..71c9e07fc3 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.Generic.cs @@ -237,7 +237,7 @@ public abstract partial class ImageFrameCollectionTests using (this.Image.Frames.CreateFrame(Color.HotPink)) { Assert.Equal(2, this.Image.Frames.Count); - this.Image.Frames[1].ComparePixelBufferTo(Color.HotPink); + this.Image.Frames[1].ComparePixelBufferTo(Color.HotPink.ToPixel()); } } diff --git a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs index f9ff6ba69e..a42dcc4812 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameCollectionTests.NonGeneric.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats.Gif; using SixLabors.ImageSharp.PixelFormats; @@ -23,13 +22,13 @@ public abstract partial class ImageFrameCollectionTests this.Image.Configuration, this.Image.Width, this.Image.Height, - Color.Blue)) + Color.Blue.ToPixel())) { this.Collection.AddFrame(sourceImage.Frames.RootFrame); } Rgba32[] expectedAllBlue = - Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); + Enumerable.Repeat(Color.Blue.ToPixel(), this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); ImageFrame actualFrame = (ImageFrame)this.Collection[1]; @@ -44,13 +43,13 @@ public abstract partial class ImageFrameCollectionTests this.Image.Configuration, this.Image.Width, this.Image.Height, - Color.Blue)) + Color.Blue.ToPixel())) { this.Collection.InsertFrame(0, sourceImage.Frames.RootFrame); } Rgba32[] expectedAllBlue = - Enumerable.Repeat((Rgba32)Color.Blue, this.Image.Width * this.Image.Height).ToArray(); + Enumerable.Repeat(Color.Blue.ToPixel(), this.Image.Width * this.Image.Height).ToArray(); Assert.Equal(2, this.Collection.Count); ImageFrame actualFrame = (ImageFrame)this.Collection[0]; @@ -177,7 +176,7 @@ public abstract partial class ImageFrameCollectionTests ImageFrame frame = (ImageFrame)this.Image.Frames[1]; - frame.ComparePixelBufferTo(Color.HotPink); + frame.ComparePixelBufferTo(Color.HotPink.ToPixel()); } [Fact] @@ -279,7 +278,7 @@ public abstract partial class ImageFrameCollectionTests { using Image source = provider.GetImage(); using Image dest = new(source.Configuration, source.Width, source.Height); - + // Giphy.gif has 5 frames ImportFrameAs(source.Frames, dest.Frames, 0); ImportFrameAs(source.Frames, dest.Frames, 1); diff --git a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs index 3b9779ea42..e09ef487a8 100644 --- a/tests/ImageSharp.Tests/Image/ImageFrameTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageFrameTests.cs @@ -35,9 +35,9 @@ public class ImageFrameTests ImageFrame frame = image.Frames.RootFrame; Rgba32 val = frame[3, 4]; Assert.Equal(default(Rgba32), val); - frame[3, 4] = Color.Red; + frame[3, 4] = Color.Red.ToPixel(); val = frame[3, 4]; - Assert.Equal(Color.Red.ToRgba32(), val); + Assert.Equal(Color.Red.ToPixel(), val); } public static TheoryData OutOfRangeData = new TheoryData() diff --git a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs index 238096be49..5762264d21 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.LoadPixelData.cs @@ -15,19 +15,17 @@ public partial class ImageTests [ValidateDisposedMemoryAllocations] public void FromPixels(bool useSpan) { - Rgba32[] data = { Color.Black, Color.White, Color.White, Color.Black, }; + Rgba32[] data = { Color.Black.ToPixel(), Color.White.ToPixel(), Color.White.ToPixel(), Color.Black.ToPixel(), }; - using (Image img = useSpan - ? Image.LoadPixelData(data.AsSpan(), 2, 2) - : Image.LoadPixelData(data, 2, 2)) - { - Assert.NotNull(img); - Assert.Equal(Color.Black, (Color)img[0, 0]); - Assert.Equal(Color.White, (Color)img[0, 1]); + using Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2); + Assert.NotNull(img); + Assert.Equal(Color.Black, Color.FromPixel(img[0, 0])); + Assert.Equal(Color.White, Color.FromPixel(img[0, 1])); - Assert.Equal(Color.White, (Color)img[1, 0]); - Assert.Equal(Color.Black, (Color)img[1, 1]); - } + Assert.Equal(Color.White, Color.FromPixel(img[1, 0])); + Assert.Equal(Color.Black, Color.FromPixel(img[1, 1])); } [Theory] @@ -36,23 +34,22 @@ public partial class ImageTests public void FromBytes(bool useSpan) { byte[] data = - { - 0, 0, 0, 255, // 0,0 - 255, 255, 255, 255, // 0,1 - 255, 255, 255, 255, // 1,0 - 0, 0, 0, 255, // 1,1 - }; - using (Image img = useSpan - ? Image.LoadPixelData(data.AsSpan(), 2, 2) - : Image.LoadPixelData(data, 2, 2)) { - Assert.NotNull(img); - Assert.Equal(Color.Black, (Color)img[0, 0]); - Assert.Equal(Color.White, (Color)img[0, 1]); + 0, 0, 0, 255, // 0,0 + 255, 255, 255, 255, // 0,1 + 255, 255, 255, 255, // 1,0 + 0, 0, 0, 255, // 1,1 + }; + + using Image img = useSpan + ? Image.LoadPixelData(data.AsSpan(), 2, 2) + : Image.LoadPixelData(data, 2, 2); + Assert.NotNull(img); + Assert.Equal(Color.Black, Color.FromPixel(img[0, 0])); + Assert.Equal(Color.White, Color.FromPixel(img[0, 1])); - Assert.Equal(Color.White, (Color)img[1, 0]); - Assert.Equal(Color.Black, (Color)img[1, 1]); - } + Assert.Equal(Color.White, Color.FromPixel(img[1, 0])); + Assert.Equal(Color.Black, Color.FromPixel(img[1, 1])); } } } diff --git a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs index 9aaefa41ef..f22a55aae6 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.WrapMemory.cs @@ -154,8 +154,8 @@ public partial class ImageTests using (var memoryManager = new BitmapMemoryManager(bmp)) { Memory memory = memoryManager.Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(memory, bmp.Width, bmp.Height)) { @@ -198,8 +198,8 @@ public partial class ImageTests using (var bmp = new Bitmap(51, 23)) { var memoryManager = new BitmapMemoryManager(bmp); - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(memoryManager, bmp.Width, bmp.Height)) { @@ -258,8 +258,8 @@ public partial class ImageTests { Memory pixelMemory = memoryManager.Memory; Memory byteMemory = new CastMemoryManager(pixelMemory).Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); using (var image = Image.WrapMemory(byteMemory, bmp.Width, bmp.Height)) { @@ -355,8 +355,8 @@ public partial class ImageTests using (var memoryManager = new BitmapMemoryManager(bmp)) { Memory pixelMemory = memoryManager.Memory; - Bgra32 bg = Color.Red; - Bgra32 fg = Color.Green; + Bgra32 bg = Color.Red.ToPixel(); + Bgra32 fg = Color.Green.ToPixel(); fixed (void* p = pixelMemory.Span) { diff --git a/tests/ImageSharp.Tests/Image/ImageTests.cs b/tests/ImageSharp.Tests/Image/ImageTests.cs index ca51f7f5cb..ac91ea948e 100644 --- a/tests/ImageSharp.Tests/Image/ImageTests.cs +++ b/tests/ImageSharp.Tests/Image/ImageTests.cs @@ -61,7 +61,7 @@ public partial class ImageTests public void Configuration_Width_Height_BackgroundColor() { Configuration configuration = Configuration.Default.Clone(); - Rgba32 color = Color.Aquamarine; + Rgba32 color = Color.Aquamarine.ToPixel(); using (Image image = new(configuration, 11, 23, color)) { @@ -116,9 +116,9 @@ public partial class ImageTests using Image image = new(this.configuration, 10, 10); Rgba32 val = image[3, 4]; Assert.Equal(default(Rgba32), val); - image[3, 4] = Color.Red; + image[3, 4] = Color.Red.ToPixel(); val = image[3, 4]; - Assert.Equal(Color.Red.ToRgba32(), val); + Assert.Equal(Color.Red.ToPixel(), val); } public static TheoryData OutOfRangeData = new() diff --git a/tests/ImageSharp.Tests/ImageInfoTests.cs b/tests/ImageSharp.Tests/ImageInfoTests.cs index 73324eccd7..576d14396e 100644 --- a/tests/ImageSharp.Tests/ImageInfoTests.cs +++ b/tests/ImageSharp.Tests/ImageInfoTests.cs @@ -1,8 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Metadata; +using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests; diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index 518aa203d9..ef99db4986 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -116,8 +115,12 @@ public class A8Tests { PixelTypeInfo info = A8.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index dbe02e9868..de6f519e1c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -151,8 +150,15 @@ public class Abgr32Tests { PixelTypeInfo info = Abgr32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index fd8ee144ba..29349b8521 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -149,8 +148,15 @@ public class Argb32Tests { PixelTypeInfo info = Argb32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 78c58e5c26..519aeb6c57 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -134,8 +133,14 @@ public class Bgr24Tests { PixelTypeInfo info = Bgr24.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 68f9532252..16e225a9bf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -256,8 +255,14 @@ public class Bgr565Tests { PixelTypeInfo info = Bgr565.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(5, componentInfo.GetComponentPrecision(0)); + Assert.Equal(6, componentInfo.GetComponentPrecision(1)); + Assert.Equal(5, componentInfo.GetComponentPrecision(2)); + Assert.Equal(6, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index e92fcf1d36..c5b4325c91 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -151,8 +150,15 @@ public class Bgra32Tests { PixelTypeInfo info = Bgra32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index 1af84c0c84..f2e9a22910 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -252,8 +251,15 @@ public class Bgra4444Tests { PixelTypeInfo info = Bgra4444.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(4, componentInfo.GetComponentPrecision(0)); + Assert.Equal(4, componentInfo.GetComponentPrecision(1)); + Assert.Equal(4, componentInfo.GetComponentPrecision(2)); + Assert.Equal(4, componentInfo.GetComponentPrecision(3)); + Assert.Equal(4, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index a0926d4ddf..03b4a41c67 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -278,8 +277,15 @@ public class Bgra5551Tests { PixelTypeInfo info = Bgra5551.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(5, componentInfo.GetComponentPrecision(0)); + Assert.Equal(5, componentInfo.GetComponentPrecision(1)); + Assert.Equal(5, componentInfo.GetComponentPrecision(2)); + Assert.Equal(1, componentInfo.GetComponentPrecision(3)); + Assert.Equal(5, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 5b456459ea..1434d7d93f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; @@ -245,8 +244,15 @@ public class Byte4Tests { PixelTypeInfo info = Byte4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 9c546e2f0c..dbd1f6917e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -74,8 +73,12 @@ public class HalfSingleTests { PixelTypeInfo info = HalfSingle.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 4f84d60871..710135ed6e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; @@ -96,8 +95,13 @@ public class HalfVector2Tests { PixelTypeInfo info = HalfVector2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 33f0173d2e..3e3f6a2ca9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -87,8 +86,15 @@ public class HalfVector4Tests { PixelTypeInfo info = HalfVector4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Half, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 0c0cdbe3bf..3a8239923e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -166,8 +165,12 @@ public class L16Tests { PixelTypeInfo info = L16.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index d8bce0640e..631a0e2346 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -261,9 +260,13 @@ public class L8Tests { PixelTypeInfo info = L8.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(1, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(1, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 46e7457a5f..9fa0e3263b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -265,9 +264,14 @@ public class La16Tests { PixelTypeInfo info = La16.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index 65aa8b1c9c..089c2076bd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -172,8 +171,13 @@ public class La32Tests { PixelTypeInfo info = La32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 999ddb9341..9f24346a0d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; @@ -88,8 +87,13 @@ public class NormalizedByte2Tests { PixelTypeInfo info = NormalizedByte2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.SByte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 64a996453b..63bb9d5f52 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -238,8 +237,15 @@ public class NormalizedByte4Tests { PixelTypeInfo info = NormalizedByte4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.SByte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index e6d4ae98d9..f262ce177b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -92,8 +91,13 @@ public class NormalizedShort2Tests { PixelTypeInfo info = NormalizedShort2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index cd684311a9..05058ae4d8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; @@ -239,8 +238,15 @@ public class NormalizedShort4Tests { PixelTypeInfo info = NormalizedShort4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs index 68cdf2d633..924e94d929 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelBlenderTests.cs @@ -43,15 +43,15 @@ public class PixelBlenderTests public static TheoryData ColorBlendingExpectedResults = new() { - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Normal, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Screen, new Rgba32(0xFFEEE7FF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.HardLight, new Rgba32(0xFFC62D32) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Overlay, new Rgba32(0xFFDDCEFF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Darken, new Rgba32(0xFF701919) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Lighten, new Rgba32(0xFFE1E4FF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Add, new Rgba32(0xFFFFFDFF) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Subtract, new Rgba32(0xFF71CBE6) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelColorBlendingMode.Multiply, new Rgba32(0xFF631619) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Normal, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Screen, new Rgba32(0xFFEEE7FF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.HardLight, new Rgba32(0xFFC62D32) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Overlay, new Rgba32(0xFFDDCEFF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Darken, new Rgba32(0xFF701919) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Lighten, new Rgba32(0xFFE1E4FF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Add, new Rgba32(0xFFFFFDFF) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Subtract, new Rgba32(0xFF71CBE6) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelColorBlendingMode.Multiply, new Rgba32(0xFF631619) }, }; [Theory] @@ -67,18 +67,18 @@ public class PixelBlenderTests public static TheoryData AlphaCompositionExpectedResults = new() { - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Clear, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Xor, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Dest, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestAtop, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestIn, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestOut, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.DestOver, Color.MistyRose }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.Src, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcAtop, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcIn, Color.MidnightBlue }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOut, new Rgba32(0) }, - { Color.MistyRose, Color.MidnightBlue, 1, PixelAlphaCompositionMode.SrcOver, Color.MidnightBlue }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Clear, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Xor, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Dest, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestAtop, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestIn, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestOut, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.DestOver, Color.MistyRose.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.Src, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcAtop, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcIn, Color.MidnightBlue.ToPixel() }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcOut, new Rgba32(0) }, + { Color.MistyRose.ToPixel(), Color.MidnightBlue.ToPixel(), 1, PixelAlphaCompositionMode.SrcOver, Color.MidnightBlue.ToPixel() }, }; [Theory] diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index bf3ff6416a..9ab1ec963c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using SixLabors.ImageSharp.Formats; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.PixelFormats; @@ -90,8 +89,13 @@ public class Rg32Tests { PixelTypeInfo info = Rg32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index c69c757b59..ab4269d009 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -137,8 +136,14 @@ public class Rgb24Tests { PixelTypeInfo info = Rgb24.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index dda5af9fb3..faf9bdb3c9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -82,8 +81,14 @@ public class Rgb48Tests { PixelTypeInfo info = Rgb48.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(3, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(3, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 5b0e4c2874..7cf8ced45f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -253,8 +252,15 @@ public class Rgba1010102Tests { PixelTypeInfo info = Rgba1010102.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(10, componentInfo.GetComponentPrecision(0)); + Assert.Equal(10, componentInfo.GetComponentPrecision(1)); + Assert.Equal(10, componentInfo.GetComponentPrecision(2)); + Assert.Equal(2, componentInfo.GetComponentPrecision(3)); + Assert.Equal(10, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index d1ad4c304a..9b96aeb7bb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -313,8 +312,15 @@ public class Rgba32Tests { PixelTypeInfo info = Rgba32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Byte, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(8, componentInfo.GetComponentPrecision(0)); + Assert.Equal(8, componentInfo.GetComponentPrecision(1)); + Assert.Equal(8, componentInfo.GetComponentPrecision(2)); + Assert.Equal(8, componentInfo.GetComponentPrecision(3)); + Assert.Equal(8, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 3dc5804604..49336400cf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -315,8 +314,15 @@ public class Rgba64Tests { PixelTypeInfo info = Rgba64.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.UShort, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 968e274e23..28ee5ace57 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -211,8 +210,15 @@ public class RgbaVectorTests { PixelTypeInfo info = RgbaVector.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Float, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(32, componentInfo.GetComponentPrecision(0)); + Assert.Equal(32, componentInfo.GetComponentPrecision(1)); + Assert.Equal(32, componentInfo.GetComponentPrecision(2)); + Assert.Equal(32, componentInfo.GetComponentPrecision(3)); + Assert.Equal(32, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 7afe61b025..d709b76059 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -167,8 +166,13 @@ public class Short2Tests { PixelTypeInfo info = Short2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(2, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(2, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index bdde5cd8f9..2b57603423 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests.PixelFormats; @@ -220,8 +219,15 @@ public class Short4Tests { PixelTypeInfo info = Short4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); - Assert.Equal(4, info.ComponentCount); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); - Assert.Equal(PixelComponentPrecision.Short, info.MaxComponentPrecision); + + PixelComponentInfo componentInfo = info.ComponentInfo.Value; + Assert.Equal(4, componentInfo.ComponentCount); + Assert.Equal(0, componentInfo.Padding); + Assert.Equal(16, componentInfo.GetComponentPrecision(0)); + Assert.Equal(16, componentInfo.GetComponentPrecision(1)); + Assert.Equal(16, componentInfo.GetComponentPrecision(2)); + Assert.Equal(16, componentInfo.GetComponentPrecision(3)); + Assert.Equal(16, componentInfo.GetMaximumComponentPrecision()); } } diff --git a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs index d6b1f1f980..ccb79debda 100644 --- a/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs +++ b/tests/ImageSharp.Tests/Quantization/WuQuantizerTests.cs @@ -14,7 +14,7 @@ public class WuQuantizerTests Configuration config = Configuration.Default; var quantizer = new WuQuantizer(new QuantizerOptions { Dither = null }); - using var image = new Image(config, 1, 1, Color.Black); + using var image = new Image(config, 1, 1, Color.Black.ToPixel()); ImageFrame frame = image.Frames.RootFrame; using IQuantizer frameQuantizer = quantizer.CreatePixelSpecificQuantizer(config); @@ -24,7 +24,7 @@ public class WuQuantizerTests Assert.Equal(1, result.Width); Assert.Equal(1, result.Height); - Assert.Equal(Color.Black, (Color)result.Palette.Span[0]); + Assert.Equal(Color.Black, Color.FromPixel(result.Palette.Span[0])); Assert.Equal(0, result.DangerousGetRowSpan(0)[0]); } diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index a4232a9688..495f5f9f63 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -263,7 +263,7 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public struct TestPixelForAgnosticDecode : IPixel { - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(2, PixelComponentPrecision.Byte, PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.None); public PixelOperations CreatePixelOperations() => new(); diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs index 8c5101013f..d78edf5bc3 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/SolidProvider.cs @@ -51,7 +51,7 @@ public abstract partial class TestImageProvider : IXunitSerializable public override Image GetImage() { Image image = base.GetImage(); - Color color = new Rgba32(this.r, this.g, this.b, this.a); + Color color = Color.FromPixel(new Rgba32(this.r, this.g, this.b, this.a)); image.GetRootFramePixelBuffer().FastMemoryGroup.Fill(color.ToPixel()); return image; From 1d352513e5436014894d48cbb239516b39bceae6 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Jan 2024 18:52:39 +1000 Subject: [PATCH 113/219] Add PixelColorType --- src/ImageSharp/PixelFormats/PixelColorType.cs | 46 +++++++++++++++++++ .../PixelFormats/PixelImplementations/A8.cs | 6 ++- .../PixelImplementations/Abgr32.cs | 6 ++- .../PixelImplementations/Argb32.cs | 6 ++- .../PixelImplementations/Bgr24.cs | 6 ++- .../PixelImplementations/Bgr565.cs | 6 ++- .../PixelImplementations/Bgra32.cs | 6 ++- .../PixelImplementations/Bgra4444.cs | 6 ++- .../PixelImplementations/Bgra5551.cs | 6 ++- .../PixelImplementations/Byte4.cs | 6 ++- .../PixelImplementations/HalfSingle.cs | 6 ++- .../PixelImplementations/HalfVector2.cs | 6 ++- .../PixelImplementations/HalfVector4.cs | 6 ++- .../PixelFormats/PixelImplementations/L16.cs | 6 ++- .../PixelFormats/PixelImplementations/L8.cs | 6 ++- .../PixelFormats/PixelImplementations/La16.cs | 6 ++- .../PixelFormats/PixelImplementations/La32.cs | 6 ++- .../PixelImplementations/NormalizedByte2.cs | 6 ++- .../PixelImplementations/NormalizedByte4.cs | 6 ++- .../PixelImplementations/NormalizedShort2.cs | 6 ++- .../PixelImplementations/NormalizedShort4.cs | 6 ++- .../PixelFormats/PixelImplementations/Rg32.cs | 6 ++- .../PixelImplementations/Rgb24.cs | 6 ++- .../PixelImplementations/Rgb48.cs | 6 ++- .../PixelImplementations/Rgba1010102.cs | 6 ++- .../PixelImplementations/Rgba32.cs | 6 ++- .../PixelImplementations/Rgba64.cs | 6 ++- .../PixelImplementations/RgbaVector.cs | 6 ++- .../PixelImplementations/Short2.cs | 6 ++- .../PixelImplementations/Short4.cs | 6 ++- src/ImageSharp/PixelFormats/PixelTypeInfo.cs | 10 +++- tests/ImageSharp.Tests/Color/RgbaDouble.cs | 6 ++- .../ImageSharp.Tests/PixelFormats/A8Tests.cs | 1 + .../PixelFormats/Abgr32Tests.cs | 1 + .../PixelFormats/Argb32Tests.cs | 1 + .../PixelFormats/Bgr24Tests.cs | 1 + .../PixelFormats/Bgr565Tests.cs | 1 + .../PixelFormats/Bgra32Tests.cs | 1 + .../PixelFormats/Bgra4444Tests.cs | 1 + .../PixelFormats/Bgra5551Tests.cs | 1 + .../PixelFormats/Byte4Tests.cs | 1 + .../PixelFormats/HalfSingleTests.cs | 1 + .../PixelFormats/HalfVector2Tests.cs | 1 + .../PixelFormats/HalfVector4Tests.cs | 1 + .../ImageSharp.Tests/PixelFormats/L16Tests.cs | 1 + .../ImageSharp.Tests/PixelFormats/L8Tests.cs | 1 + .../PixelFormats/La16Tests.cs | 1 + .../PixelFormats/La32Tests.cs | 1 + .../PixelFormats/NormalizedByte2Tests.cs | 1 + .../PixelFormats/NormalizedByte4Tests.cs | 1 + .../PixelFormats/NormalizedShort2Tests.cs | 1 + .../PixelFormats/NormalizedShort4Tests.cs | 1 + .../PixelFormats/Rg32Tests.cs | 1 + .../PixelFormats/Rgb24Tests.cs | 1 + .../PixelFormats/Rgb48Tests.cs | 1 + .../PixelFormats/Rgba1010102Tests.cs | 1 + .../PixelFormats/Rgba32Tests.cs | 1 + .../PixelFormats/Rgba64Tests.cs | 1 + .../PixelFormats/RgbaVectorTests.cs | 1 + .../PixelFormats/Short2Tests.cs | 1 + .../PixelFormats/Short4Tests.cs | 1 + tests/ImageSharp.Tests/TestFormat.cs | 6 ++- 62 files changed, 239 insertions(+), 32 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelColorType.cs diff --git a/src/ImageSharp/PixelFormats/PixelColorType.cs b/src/ImageSharp/PixelFormats/PixelColorType.cs new file mode 100644 index 0000000000..9ac2c308c2 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelColorType.cs @@ -0,0 +1,46 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Represents the color type and format of a pixel. +/// +[Flags] +public enum PixelColorType +{ + /// + /// Represents the Red component of the color. + /// + Red = 1 << 0, + + /// + /// Represents the Green component of the color. + /// + Green = 1 << 1, + + /// + /// Represents the Blue component of the color. + /// + Blue = 1 << 2, + + /// + /// Represents the Alpha component of the color for transparency. + /// + Alpha = 1 << 3, + + /// + /// Indicates that the color is in grayscale. + /// + Grayscale = 1 << 4, + + /// + /// Indicates that the color is in RGB (Red, Green, Blue) format. + /// + RGB = Red | Green | Blue | (1 << 5), + + /// + /// Indicates that the color is in BGR (Blue, Green, Red) format. + /// + BGR = Blue | Green | Red | (1 << 6) +} diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index abae4f246f..23dae82abe 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -56,7 +56,11 @@ public partial struct A8 : IPixel, IPackedVector public static bool operator !=(A8 left, A8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 8), + PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index e1399f05c0..742f27cc02 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -168,7 +168,11 @@ public partial struct Abgr32 : IPixel, IPackedVector public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.Alpha | PixelColorType.BGR, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 2b7bcf9133..7a8ee2a63a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -168,7 +168,11 @@ public partial struct Argb32 : IPixel, IPackedVector public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.Alpha | PixelColorType.RGB, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index c9c3246807..bdf7d1a7e2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -72,7 +72,11 @@ public partial struct Bgr24 : IPixel public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 8, 8, 8), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 8, 8, 8), + PixelColorType.BGR, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index d020cf0256..0874eb8251 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -60,7 +60,11 @@ public partial struct Bgr565 : IPixel, IPackedVector public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 5, 6, 5), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 5, 6, 5), + PixelColorType.BGR, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index b3a96523ee..f508463574 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -121,7 +121,11 @@ public partial struct Bgra32 : IPixel, IPackedVector public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 510d6666f7..4bb3f8a0e8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -58,7 +58,11 @@ public partial struct Bgra4444 : IPixel, IPackedVector public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 4, 4, 4, 4), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 4, 4, 4, 4), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 68dbd9544e..d57545deea 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -61,7 +61,11 @@ public partial struct Bgra5551 : IPixel, IPackedVector public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 5, 5, 5, 1), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 5, 5, 5, 1), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index fbe7a0c52f..d8f1dd0acb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -61,7 +61,11 @@ public partial struct Byte4 : IPixel, IPackedVector public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index aca64ae7a0..01ae9fc5f5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -46,7 +46,11 @@ public partial struct HalfSingle : IPixel, IPackedVector public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 16), + PixelColorType.Red, + PixelAlphaRepresentation.None); /// public PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 5a25d523bb..d591dd8550 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -53,7 +53,11 @@ public partial struct HalfVector2 : IPixel, IPackedVector public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 7ad7b07f40..ca6bff2305 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -58,7 +58,11 @@ public partial struct HalfVector4 : IPixel, IPackedVector public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 0c58fb1fda..8522da3fbc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -48,7 +48,11 @@ public partial struct L16 : IPixel, IPackedVector public static bool operator !=(L16 left, L16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 16), + PixelColorType.Grayscale, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 2cd8b20e77..706fc11014 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -49,7 +49,11 @@ public partial struct L8 : IPixel, IPackedVector public static bool operator !=(L8 left, L8 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(1, 8), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 8), + PixelColorType.Grayscale, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index b811df4b4d..e306731534 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -72,7 +72,11 @@ public partial struct La16 : IPixel, IPackedVector public static bool operator !=(La16 left, La16 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Grayscale | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index e6a63f5ec1..867bfacd36 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -74,7 +74,11 @@ public partial struct La32 : IPixel, IPackedVector public static bool operator !=(La32 left, La32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Grayscale | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index f7427e65ce..c5eb2c2ded 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -61,7 +61,11 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index beeae655a0..6cf92688ed 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -63,7 +63,11 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 8152c89d37..03fa2737ee 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -62,7 +62,11 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 3f37cb80f7..89ba2a23ba 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -64,7 +64,11 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 594bdd9a13..8f2e198405 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -58,7 +58,11 @@ public partial struct Rg32 : IPixel, IPackedVector public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 8d0c7cd48c..008de06bfb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -91,7 +91,11 @@ public partial struct Rgb24 : IPixel public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 8, 8, 8), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 8, 8, 8), + PixelColorType.RGB, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index f7aac32f42..ae4d6dc011 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -70,7 +70,11 @@ public partial struct Rgb48 : IPixel public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(3, 16, 16, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(3, 16, 16, 16), + PixelColorType.RGB, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 84482a7aaa..ac1eedb072 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -61,7 +61,11 @@ public partial struct Rgba1010102 : IPixel, IPackedVector public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 10, 10, 10, 2), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 10, 10, 10, 2), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index f391e64740..8b2a078db6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -271,7 +271,11 @@ public partial struct Rgba32 : IPixel, IPackedVector } /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 8, 8, 8, 8), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 47062779ba..b71ec5f353 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -191,7 +191,11 @@ public partial struct Rgba64 : IPixel, IPackedVector public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index ce1c6d5729..cd61b13b24 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -97,7 +97,11 @@ public partial struct RgbaVector : IPixel public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 32, 32, 32, 32), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 32, 32, 32, 32), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 786c98ee46..c8819337ed 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -65,7 +65,11 @@ public partial struct Short2 : IPixel, IPackedVector public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 16, 16), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 890e66299a..cfd9ce0bfb 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -67,7 +67,11 @@ public partial struct Short4 : IPixel, IPackedVector public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 16, 16, 16, 16), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); diff --git a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs index e209b21e12..81c70a18f7 100644 --- a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs +++ b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs @@ -23,10 +23,15 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) public int BitsPerPixel { get; init; } = bitsPerPixel; /// - /// Gets the maximum precision of components within the pixel. + /// Gets the component bit depth and padding within the pixel. /// public PixelComponentInfo? ComponentInfo { get; init; } + /// + /// Gets the pixel color type. + /// + public PixelColorType? ColorType { get; init; } + /// /// Gets the pixel alpha transparency behavior. /// means unknown, unspecified. @@ -38,16 +43,19 @@ public readonly struct PixelTypeInfo(int bitsPerPixel) /// /// The type of pixel format. /// The pixel component info. + /// The pixel color type. /// The pixel alpha representation. /// The . public static PixelTypeInfo Create( PixelComponentInfo info, + PixelColorType colorType, PixelAlphaRepresentation alphaRepresentation) where TPixel : unmanaged, IPixel => new() { BitsPerPixel = Unsafe.SizeOf() * 8, ComponentInfo = info, + ColorType = colorType, AlphaRepresentation = alphaRepresentation }; } diff --git a/tests/ImageSharp.Tests/Color/RgbaDouble.cs b/tests/ImageSharp.Tests/Color/RgbaDouble.cs index 476ff03365..fdd736930d 100644 --- a/tests/ImageSharp.Tests/Color/RgbaDouble.cs +++ b/tests/ImageSharp.Tests/Color/RgbaDouble.cs @@ -77,7 +77,11 @@ public partial struct RgbaDouble(double r, double g, double b, double a = 1) : I public static bool operator !=(RgbaDouble left, RgbaDouble right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(4, 64, 64, 64, 64), PixelAlphaRepresentation.Unassociated); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 64, 64, 64, 64), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// public readonly PixelOperations CreatePixelOperations() => new(); diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index ef99db4986..b7a86d488c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -116,6 +116,7 @@ public class A8Tests PixelTypeInfo info = A8.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(1, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index de6f519e1c..7f584b1bf5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -151,6 +151,7 @@ public class Abgr32Tests PixelTypeInfo info = Abgr32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha | PixelColorType.BGR, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 29349b8521..42b940845d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -149,6 +149,7 @@ public class Argb32Tests PixelTypeInfo info = Argb32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Alpha | PixelColorType.RGB, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 519aeb6c57..239e883960 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -134,6 +134,7 @@ public class Bgr24Tests PixelTypeInfo info = Bgr24.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(3, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 16e225a9bf..2ad4f4cf7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -256,6 +256,7 @@ public class Bgr565Tests PixelTypeInfo info = Bgr565.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(3, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index c5b4325c91..df8d1199f2 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -151,6 +151,7 @@ public class Bgra32Tests PixelTypeInfo info = Bgra32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index f2e9a22910..ef587f3011 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -252,6 +252,7 @@ public class Bgra4444Tests PixelTypeInfo info = Bgra4444.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 03b4a41c67..5140cfda1a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -278,6 +278,7 @@ public class Bgra5551Tests PixelTypeInfo info = Bgra5551.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.BGR | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index 1434d7d93f..a61318db7c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -245,6 +245,7 @@ public class Byte4Tests PixelTypeInfo info = Byte4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index dbd1f6917e..3e84da7231 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -74,6 +74,7 @@ public class HalfSingleTests PixelTypeInfo info = HalfSingle.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(1, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 710135ed6e..04e3ee35fe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -96,6 +96,7 @@ public class HalfVector2Tests PixelTypeInfo info = HalfVector2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index 3e3f6a2ca9..e8420ddd0d 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -87,6 +87,7 @@ public class HalfVector4Tests PixelTypeInfo info = HalfVector4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 3a8239923e..337d02084a 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -166,6 +166,7 @@ public class L16Tests PixelTypeInfo info = L16.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Grayscale, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(1, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index 631a0e2346..81f4d61fba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -261,6 +261,7 @@ public class L8Tests PixelTypeInfo info = L8.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Grayscale, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(1, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 9fa0e3263b..612d0f81af 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -265,6 +265,7 @@ public class La16Tests PixelTypeInfo info = La16.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Grayscale | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index 089c2076bd..f55707c05b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -172,6 +172,7 @@ public class La32Tests PixelTypeInfo info = La32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Grayscale | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 9f24346a0d..89c0ae69f7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -88,6 +88,7 @@ public class NormalizedByte2Tests PixelTypeInfo info = NormalizedByte2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 63bb9d5f52..297438c65e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -238,6 +238,7 @@ public class NormalizedByte4Tests PixelTypeInfo info = NormalizedByte4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index f262ce177b..4b912d8667 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -92,6 +92,7 @@ public class NormalizedShort2Tests PixelTypeInfo info = NormalizedShort2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 05058ae4d8..0d97658882 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -239,6 +239,7 @@ public class NormalizedShort4Tests PixelTypeInfo info = NormalizedShort4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index 9ab1ec963c..fac7678124 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -90,6 +90,7 @@ public class Rg32Tests PixelTypeInfo info = Rg32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index ab4269d009..385126a65b 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -137,6 +137,7 @@ public class Rgb24Tests PixelTypeInfo info = Rgb24.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(3, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index faf9bdb3c9..625a9187fe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -82,6 +82,7 @@ public class Rgb48Tests PixelTypeInfo info = Rgb48.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(3, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index 7cf8ced45f..a8243064d3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -253,6 +253,7 @@ public class Rgba1010102Tests PixelTypeInfo info = Rgba1010102.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 9b96aeb7bb..35fab151c7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -313,6 +313,7 @@ public class Rgba32Tests PixelTypeInfo info = Rgba32.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 49336400cf..4f335b1e81 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -315,6 +315,7 @@ public class Rgba64Tests PixelTypeInfo info = Rgba64.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index 28ee5ace57..b263bf8ea7 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -211,6 +211,7 @@ public class RgbaVectorTests PixelTypeInfo info = RgbaVector.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index d709b76059..1143925cb3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -167,6 +167,7 @@ public class Short2Tests PixelTypeInfo info = Short2.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.None, info.AlphaRepresentation); + Assert.Equal(PixelColorType.Red | PixelColorType.Green, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(2, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index 2b57603423..ab3cc3b6e5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -220,6 +220,7 @@ public class Short4Tests PixelTypeInfo info = Short4.GetPixelTypeInfo(); Assert.Equal(Unsafe.SizeOf() * 8, info.BitsPerPixel); Assert.Equal(PixelAlphaRepresentation.Unassociated, info.AlphaRepresentation); + Assert.Equal(PixelColorType.RGB | PixelColorType.Alpha, info.ColorType); PixelComponentInfo componentInfo = info.ComponentInfo.Value; Assert.Equal(4, componentInfo.ComponentCount); diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 495f5f9f63..983cf4d46b 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -263,7 +263,11 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public struct TestPixelForAgnosticDecode : IPixel { - public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create(PixelComponentInfo.Create(2, 8, 8), PixelAlphaRepresentation.None); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 8, 8), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); public PixelOperations CreatePixelOperations() => new(); From 057edd8ddd010f3f83446568c54c6565a9c4a171 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Jan 2024 20:05:06 +1000 Subject: [PATCH 114/219] Use the new metadata --- src/ImageSharp/Color/Color.cs | 4 +- src/ImageSharp/Formats/Png/PngBitDepth.cs | 2 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 104 ++++++++++-------- .../PixelFormats/PixelComponentBitDepth.cs | 50 +++++++++ .../PixelFormats/PixelComponentPrecision.cs | 70 ------------ src/ImageSharp/PixelFormats/PixelTypeInfo.cs | 3 +- .../Formats/Png/PngEncoderTests.cs | 20 ++-- 7 files changed, 125 insertions(+), 128 deletions(-) create mode 100644 src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs delete mode 100644 src/ImageSharp/PixelFormats/PixelComponentPrecision.cs diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index ec19a86eb9..e61abf86fc 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -94,7 +94,7 @@ public readonly partial struct Color : IEquatable { // Avoid boxing in case we can convert to Vector4 safely and efficiently PixelTypeInfo info = TPixel.GetPixelTypeInfo(); - if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32) { return new(pixel.ToScaledVector4()); } @@ -118,7 +118,7 @@ public readonly partial struct Color : IEquatable // Avoid boxing in case we can convert to Vector4 safely and efficiently PixelTypeInfo info = TPixel.GetPixelTypeInfo(); - if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentPrecision.Float) + if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32) { for (int i = 0; i < destination.Length; i++) { diff --git a/src/ImageSharp/Formats/Png/PngBitDepth.cs b/src/ImageSharp/Formats/Png/PngBitDepth.cs index 452839d1d4..a5cd2026b2 100644 --- a/src/ImageSharp/Formats/Png/PngBitDepth.cs +++ b/src/ImageSharp/Formats/Png/PngBitDepth.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. // Note the value assignment, This will allow us to add 1, 2, and 4 bit encoding when we support it. diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 8bf8be2adc..aa3603cfbb 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -1466,23 +1466,48 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable // Use options, then check metadata, if nothing set there then we suggest // a sensible default based upon the pixel format. - this.colorType = encoder.ColorType ?? pngMetadata.ColorType ?? SuggestColorType(); - if (!encoder.FilterMethod.HasValue) + PngColorType? colorType = encoder.ColorType ?? pngMetadata.ColorType; + byte? bits = (byte?)(encoder.BitDepth ?? pngMetadata.BitDepth); + + if (colorType is null || bits is null) { - // Specification recommends default filter method None for paletted images and Paeth for others. - this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth; + PixelTypeInfo info = TPixel.GetPixelTypeInfo(); + PixelComponentInfo? componentInfo = info.ComponentInfo; + + colorType ??= SuggestColorType(in info); + + if (bits is null) + { + // TODO: Update once we stop abusing PixelTypeInfo in decoders. + if (componentInfo.HasValue) + { + PixelComponentInfo c = componentInfo.Value; + bits = (byte)SuggestBitDepth(in c); + } + else + { + bits = (byte)PngBitDepth.Bit8; + } + } } // Ensure bit depth and color type are a supported combination. // Bit8 is the only bit depth supported by all color types. - byte bits = (byte)(encoder.BitDepth ?? pngMetadata.BitDepth ?? SuggestBitDepth()); - byte[] validBitDepths = PngConstants.ColorTypes[this.colorType]; + byte[] validBitDepths = PngConstants.ColorTypes[colorType.Value]; if (Array.IndexOf(validBitDepths, bits) == -1) { bits = (byte)PngBitDepth.Bit8; } - this.bitDepth = bits; + this.colorType = colorType.Value; + this.bitDepth = bits.Value; + + if (!encoder.FilterMethod.HasValue) + { + // Specification recommends default filter method None for paletted images and Paeth for others. + this.filterMethod = this.colorType is PngColorType.Palette ? PngFilterMethod.None : PngFilterMethod.Paeth; + } + use16Bit = bits == (byte)PngBitDepth.Bit16; bytesPerPixel = CalculateBytesPerPixel(this.colorType, use16Bit); @@ -1611,53 +1636,44 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable /// /// Returns a suggested for the given - /// This is not exhaustive but covers many common pixel formats. /// + /// The pixel type info. /// The type of pixel format. - private static PngColorType SuggestColorType() + private static PngColorType SuggestColorType(in PixelTypeInfo info) where TPixel : unmanaged, IPixel - => default(TPixel) switch - { - A8 => PngColorType.GrayscaleWithAlpha, - Argb32 => PngColorType.RgbWithAlpha, - Bgr24 => PngColorType.Rgb, - Bgra32 => PngColorType.RgbWithAlpha, - L8 => PngColorType.Grayscale, - L16 => PngColorType.Grayscale, - La16 => PngColorType.GrayscaleWithAlpha, - La32 => PngColorType.GrayscaleWithAlpha, - Rgb24 => PngColorType.Rgb, - Rgba32 => PngColorType.RgbWithAlpha, - Rgb48 => PngColorType.Rgb, - Rgba64 => PngColorType.RgbWithAlpha, - RgbaVector => PngColorType.RgbWithAlpha, - _ => PngColorType.RgbWithAlpha + { + if (info.AlphaRepresentation == PixelAlphaRepresentation.None) + { + return info.ColorType switch + { + PixelColorType.Grayscale => PngColorType.Grayscale, + _ => PngColorType.Rgb, + }; + } + + return info.ColorType switch + { + PixelColorType.Grayscale | PixelColorType.Alpha or PixelColorType.Alpha => PngColorType.GrayscaleWithAlpha, + _ => PngColorType.RgbWithAlpha, }; + } /// /// Returns a suggested for the given - /// This is not exhaustive but covers many common pixel formats. /// + /// The pixel type info. /// The type of pixel format. - private static PngBitDepth SuggestBitDepth() + private static PngBitDepth SuggestBitDepth(in PixelComponentInfo info) where TPixel : unmanaged, IPixel - => default(TPixel) switch - { - A8 => PngBitDepth.Bit8, - Argb32 => PngBitDepth.Bit8, - Bgr24 => PngBitDepth.Bit8, - Bgra32 => PngBitDepth.Bit8, - L8 => PngBitDepth.Bit8, - L16 => PngBitDepth.Bit16, - La16 => PngBitDepth.Bit8, - La32 => PngBitDepth.Bit16, - Rgb24 => PngBitDepth.Bit8, - Rgba32 => PngBitDepth.Bit8, - Rgb48 => PngBitDepth.Bit16, - Rgba64 => PngBitDepth.Bit16, - RgbaVector => PngBitDepth.Bit16, - _ => PngBitDepth.Bit8 - }; + { + int bits = info.GetMaximumComponentPrecision(); + if (bits > (int)PixelComponentBitDepth.Bit8) + { + return PngBitDepth.Bit16; + } + + return PngBitDepth.Bit8; + } private unsafe struct ScratchBuffer { diff --git a/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs b/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs new file mode 100644 index 0000000000..674c9363b5 --- /dev/null +++ b/src/ImageSharp/PixelFormats/PixelComponentBitDepth.cs @@ -0,0 +1,50 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.PixelFormats; + +/// +/// Provides enumeration of the precision in bits of individual components within a pixel format. +/// +public enum PixelComponentBitDepth +{ + /// + /// 1 bit per component. + /// + Bit1 = 1, + + /// + /// 2 bits per component. + /// + Bit2 = 2, + + /// + /// 4 bits per component. + /// + Bit4 = 4, + + /// + /// 8 bits per component. + /// + Bit8 = 8, + + /// + /// 16 bits per component. + /// + Bit16 = 16, + + /// + /// 32 bits per component. + /// + Bit32 = 32, + + /// + /// 64 bits per component. + /// + Bit64 = 64, + + /// + /// 128 bits per component. + /// + Bit128 = 128 +} diff --git a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs b/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs deleted file mode 100644 index 2f15b7fad8..0000000000 --- a/src/ImageSharp/PixelFormats/PixelComponentPrecision.cs +++ /dev/null @@ -1,70 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -namespace SixLabors.ImageSharp.PixelFormats; - -/// -/// Provides enumeration of the precision in bits of individual components within a pixel format. -/// -public enum PixelComponentPrecision -{ - /// - /// 8-bit signed integer. - /// - SByte = sizeof(sbyte) * 8, - - /// - /// 8-bit unsigned integer. - /// - Byte = sizeof(byte) * 8, - - /// - /// 16-bit signed integer. - /// - Short = sizeof(short) * 8, - - /// - /// 16-bit unsigned integer. - /// - UShort = sizeof(ushort) * 8, - - /// - /// 32-bit signed integer. - /// - Int = sizeof(int) * 8, - - /// - /// 32-bit unsigned integer. - /// - UInt = sizeof(uint) * 8, - - /// - /// 64-bit signed integer. - /// - Long = sizeof(long) * 8, - - /// - /// 64-bit unsigned integer. - /// - ULong = sizeof(ulong) * 8, - - /// - /// 16-bit floating point. - /// - Half = (sizeof(float) * 8) / 2, - - /// - /// 32-bit floating point. - /// - Float = sizeof(float) * 8, - - /// - /// 64-bit floating point. - /// - Double = sizeof(double) * 8, - - /// - /// 128-bit floating point. - /// - Decimal = sizeof(decimal) * 8, -} diff --git a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs index 81c70a18f7..7cd1284f48 100644 --- a/src/ImageSharp/PixelFormats/PixelTypeInfo.cs +++ b/src/ImageSharp/PixelFormats/PixelTypeInfo.cs @@ -4,8 +4,9 @@ using System.Runtime.CompilerServices; // TODO: Review this type as it's used to represent 2 different things. -// 1.The encoded image pixel format. +// 1. The encoded image pixel format. // 2. The pixel format of the decoded image. +// Only the bits per pixel is used by the decoder, we should make it a property of the image metadata. namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 477d88e9a8..825becb36a 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -256,21 +256,21 @@ public partial class PngEncoderTests [Theory] [WithBlankImages(1, 1, PixelTypes.A8, PngColorType.GrayscaleWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Argb32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.Bgr565, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Bgr565, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgra4444, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Byte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.HalfSingle, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.HalfVector2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.HalfVector4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.NormalizedByte2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.HalfSingle, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.HalfVector2, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.HalfVector4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.NormalizedByte2, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.NormalizedByte4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.NormalizedShort4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.Rg32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.Rgba1010102, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.NormalizedShort4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.Rg32, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.Rgba1010102, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] [WithBlankImages(1, 1, PixelTypes.Rgba32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.RgbaVector, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] - [WithBlankImages(1, 1, PixelTypes.Short2, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] - [WithBlankImages(1, 1, PixelTypes.Short4, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] + [WithBlankImages(1, 1, PixelTypes.Short2, PngColorType.Rgb, PngBitDepth.Bit16)] + [WithBlankImages(1, 1, PixelTypes.Short4, PngColorType.RgbWithAlpha, PngBitDepth.Bit16)] [WithBlankImages(1, 1, PixelTypes.Rgb24, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgr24, PngColorType.Rgb, PngBitDepth.Bit8)] [WithBlankImages(1, 1, PixelTypes.Bgra32, PngColorType.RgbWithAlpha, PngBitDepth.Bit8)] From 029381e2d3b15743b615db80d5fdbf4f5275a259 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 5 Jan 2024 20:26:32 +1000 Subject: [PATCH 115/219] Remove outdated rule overrides. --- shared-infrastructure | 2 +- src/ImageSharp.ruleset | 2 -- 2 files changed, 1 insertion(+), 3 deletions(-) diff --git a/shared-infrastructure b/shared-infrastructure index 1c526a97ee..d65232bbbf 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit 1c526a97eea8bcbc7c79de095676f7fb975a9fb1 +Subproject commit d65232bbbfe55a9a153b4058139dda5230e6eb4f diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index 6c291bfb12..f29278c95f 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -2,7 +2,5 @@ - - From bb9ed6533370ed83ee7adc7d507d5b1f3929fa89 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Sun, 7 Jan 2024 15:49:34 +0100 Subject: [PATCH 116/219] add jpeg com marker support --- ImageSharp.sln | 1 + .../Formats/Jpeg/JpegDecoderCore.cs | 20 ++++++++- .../Formats/Jpeg/JpegEncoderCore.cs | 45 +++++++++++++++++++ src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 7 +++ .../Formats/Jpeg/MetadataExtensions.cs | 21 +++++++++ .../Formats/Jpg/JpegDecoderTests.cs | 15 +++++++ .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 44 ++++++++++++++++++ .../Formats/Jpg/JpegMetadataTests.cs | 24 +++++++++- tests/ImageSharp.Tests/TestImages.cs | 1 + .../Input/Jpg/issues/issue-2067-comment.jpg | 3 ++ 10 files changed, 179 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/issue-2067-comment.jpg diff --git a/ImageSharp.sln b/ImageSharp.sln index 2967acb8ff..82eeefcde6 100644 --- a/ImageSharp.sln +++ b/ImageSharp.sln @@ -237,6 +237,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "issues", "issues", "{5C9B68 tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg = tests\Images\Input\Jpg\issues\issue750-exif-tranform.jpg tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg = tests\Images\Input\Jpg\issues\Issue845-Incorrect-Quality99.jpg tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg = tests\Images\Input\Jpg\issues\issue855-incorrect-colorspace.jpg + tests\Images\Input\Jpg\issues\issue-2067-comment.jpg = tests\Images\Input\Jpg\issues\issue-2067-comment.jpg EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "fuzz", "fuzz", "{516A3532-6AC2-417B-AD79-9BD5D0D378A0}" diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index ccace190f9..e11923ac8c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -6,6 +6,7 @@ using System.Buffers; using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Text; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; @@ -481,7 +482,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals case JpegConstants.Markers.APP15: case JpegConstants.Markers.COM: - stream.Skip(markerContentByteSize); + this.ProcessComMarker(stream, markerContentByteSize); break; case JpegConstants.Markers.DAC: @@ -515,6 +516,23 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals this.scanDecoder = null; } + /// + /// Assigns COM marker bytes to comment property + /// + /// The input stream. + /// The remaining bytes in the segment block. + private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) + { + Span temp = stackalloc byte[markerContentByteSize]; + char[] chars = new char[markerContentByteSize]; + JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); + + stream.Read(temp); + Encoding.ASCII.GetChars(temp, chars); + + metadata.Comments.Add(chars); + } + /// /// Returns encoded colorspace based on the adobe APP14 marker. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 7fc2a1f45e..cc6042b6ef 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -3,6 +3,7 @@ #nullable disable using System.Buffers.Binary; +using System.Text; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; @@ -89,6 +90,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals // Write Exif, XMP, ICC and IPTC profiles this.WriteProfiles(metadata, buffer); + // Write comments + this.WriteComment(jpegMetadata); + // Write the image dimensions. this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer); @@ -167,6 +171,47 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals this.outputStream.Write(buffer, 0, 18); } + /// + /// Writes comment + /// + /// The image metadata. + private void WriteComment(JpegMetadata metadata) + { + if (metadata.Comments is { Count: 0 }) + { + return; + } + + // Length (comment strings lengths) + (comments markers with payload sizes) + int commentsBytes = metadata.Comments.Sum(x => x.Length) + (metadata.Comments.Count * 4); + int commentStart = 0; + Span commentBuffer = stackalloc byte[commentsBytes]; + + foreach (Memory comment in metadata.Comments) + { + int totalComLength = comment.Length + 4; + + Span commentData = commentBuffer.Slice(commentStart, totalComLength); + Span markers = commentData.Slice(0, 2); + Span payloadSize = commentData.Slice(2, 2); + Span payload = commentData.Slice(4, comment.Length); + + // Beginning of comment ff fe + markers[0] = JpegConstants.Markers.XFF; + markers[1] = JpegConstants.Markers.COM; + + // Write payload size + BinaryPrimitives.WriteInt16BigEndian(payloadSize, (short)(commentData.Length - 2)); + + Encoding.ASCII.GetBytes(comment.Span, payload); + + // Indicate begin of next comment in buffer + commentStart += totalComLength; + } + + this.outputStream.Write(commentBuffer, 0, commentBuffer.Length); + } + /// /// Writes the Define Huffman Table marker and tables. /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index 59fc2f9cba..61fe3b214e 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -15,6 +15,7 @@ public class JpegMetadata : IDeepCloneable /// public JpegMetadata() { + this.Comments = new List>(); } /// @@ -25,6 +26,7 @@ public class JpegMetadata : IDeepCloneable { this.ColorType = other.ColorType; + this.Comments = other.Comments; this.LuminanceQuality = other.LuminanceQuality; this.ChrominanceQuality = other.ChrominanceQuality; } @@ -101,6 +103,11 @@ public class JpegMetadata : IDeepCloneable /// public bool? Progressive { get; internal set; } + /// + /// Gets the comments. + /// + public ICollection>? Comments { get; } + /// public IDeepCloneable DeepClone() => new JpegMetadata(this); } diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs index 753dfdb60e..53efc7d0ca 100644 --- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Text; using SixLabors.ImageSharp.Formats.Jpeg; using SixLabors.ImageSharp.Metadata; @@ -17,4 +18,24 @@ public static partial class MetadataExtensions /// The metadata this method extends. /// The . public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance); + + /// + /// Saves the comment into + /// + /// The metadata this method extends. + /// The comment string. + public static void SaveComment(this JpegMetadata metadata, string comment) + { + ASCIIEncoding encoding = new(); + + byte[] bytes = encoding.GetBytes(comment); + metadata.Comments?.Add(encoding.GetChars(bytes)); + } + + /// + /// Gets the comments from + /// + /// The metadata this method extends. + /// The IEnumerable string of comments. + public static IEnumerable? GetComments(this JpegMetadata metadata) => metadata.Comments?.Select(x => x.ToString()); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index c8d93f6e9e..b219e715f6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -364,4 +364,19 @@ public partial class JpegDecoderTests image.DebugSave(provider); image.CompareToOriginal(provider); } + + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] + public void JpegDecoder_DecodeMetadataComment(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + string expectedComment = "TEST COMMENT"; + using Image image = provider.GetImage(JpegDecoder.Instance); + JpegMetadata metadata = image.Metadata.GetJpegMetadata(); + + Assert.Equal(1, metadata.Comments?.Count); + Assert.Equal(expectedComment, metadata.GetComments()?.FirstOrDefault()); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index 2b721b9b51..50f47a1345 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -154,6 +154,50 @@ public partial class JpegEncoderTests } } + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] + public void Encode_PreservesComments(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + // arrange + using var input = provider.GetImage(JpegDecoder.Instance); + using var memStream = new MemoryStream(); + + // act + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(1, actual.Comments.Count); + Assert.Equal("TEST COMMENT", actual.Comments.ElementAt(0).ToString()); + } + + [Fact] + public void Encode_SavesMultipleComments() + { + // arrange + using var input = new Image(1, 1); + JpegMetadata meta = input.Metadata.GetJpegMetadata(); + using var memStream = new MemoryStream(); + + // act + meta.SaveComment("First comment"); + meta.SaveComment("Second Comment"); + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using var output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(2, actual.Comments.Count); + Assert.Equal(meta.Comments.ElementAt(0).ToString(), actual.Comments.ElementAt(0).ToString()); + Assert.Equal(meta.Comments.ElementAt(1).ToString(), actual.Comments.ElementAt(1).ToString()); + } + [Theory] [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingColor.Luminance)] [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 05f22667dc..901bb4619a 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Collections.ObjectModel; using SixLabors.ImageSharp.Formats.Jpeg; namespace SixLabors.ImageSharp.Tests.Formats.Jpg; @@ -55,6 +56,27 @@ public class JpegMetadataTests var meta = new JpegMetadata { LuminanceQuality = qualityLuma, ChrominanceQuality = qualityChroma }; - Assert.Equal(meta.Quality, qualityLuma); + Assert.Equal(meta.Quality, qualityLuma); + } + + [Fact] + public void Comment_EmptyComment() + { + var meta = new JpegMetadata(); + + Assert.True(Array.Empty>().SequenceEqual(meta.Comments)); + } + + [Fact] + public void Comment_OnlyComment() + { + string comment = "test comment"; + var expectedCollection = new Collection> { new(comment.ToCharArray()) }; + + var meta = new JpegMetadata(); + meta.Comments?.Add(comment.ToCharArray()); + + Assert.Equal(1, meta.Comments?.Count); + Assert.True(expectedCollection.FirstOrDefault().ToString() == meta.Comments?.FirstOrDefault().ToString()); } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8aa95d3496..0dab4ff87b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -309,6 +309,7 @@ public static class TestImages public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; + public const string Issue2067_CommentMarker = "Jpg/issues/issue-2067-comment.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg b/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg new file mode 100644 index 0000000000..18dc6f2e32 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/issue-2067-comment.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:d87b5429adeffcfac535aa8af2ec9801bf6c965a2e6751cfec4f8534195ba8f4 +size 21082 From b3a8452edc95ed4603b13fc78dab90394b5a2891 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Sun, 7 Jan 2024 18:53:03 +0100 Subject: [PATCH 117/219] Rename SaveComment to SetComment, add index, add clearcomments --- .../Formats/Jpeg/MetadataExtensions.cs | 23 +++++++++++++++---- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 15 ++++++++++++ .../Formats/Jpg/JpegDecoderTests.cs | 15 ------------ .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 10 ++++---- 4 files changed, 38 insertions(+), 25 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs index 53efc7d0ca..0c66fcbdd7 100644 --- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs @@ -20,22 +20,35 @@ public static partial class MetadataExtensions public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance); /// - /// Saves the comment into + /// Sets the comment in /// /// The metadata this method extends. + /// The index of comment to be inserted to. /// The comment string. - public static void SaveComment(this JpegMetadata metadata, string comment) + public static void SetComment(this JpegMetadata metadata, int index, string comment) { - ASCIIEncoding encoding = new(); + if (metadata.Comments == null) + { + return; + } + ASCIIEncoding encoding = new(); byte[] bytes = encoding.GetBytes(comment); - metadata.Comments?.Add(encoding.GetChars(bytes)); + List>? comments = metadata.Comments as List>; + comments?.Insert(index, encoding.GetChars(bytes)); } /// /// Gets the comments from /// /// The metadata this method extends. + /// The index of comment. /// The IEnumerable string of comments. - public static IEnumerable? GetComments(this JpegMetadata metadata) => metadata.Comments?.Select(x => x.ToString()); + public static string? GetComment(this JpegMetadata metadata, int index) => metadata.Comments?.ElementAtOrDefault(index).ToString(); + + /// + /// Clears comments + /// + /// The . + public static void ClearComments(this JpegMetadata metadata) => metadata.Comments?.Clear(); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 1c203e7342..fb37a956d0 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -425,6 +425,21 @@ public partial class JpegDecoderTests VerifyEncodedStrings(exif); } + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] + public void JpegDecoder_DecodeMetadataComment(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + string expectedComment = "TEST COMMENT"; + using Image image = provider.GetImage(JpegDecoder.Instance); + JpegMetadata metadata = image.Metadata.GetJpegMetadata(); + + Assert.Equal(1, metadata.Comments?.Count); + Assert.Equal(expectedComment, metadata.GetComment(0)); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } + private static void VerifyEncodedStrings(ExifProfile exif) { Assert.NotNull(exif); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index b219e715f6..c8d93f6e9e 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -364,19 +364,4 @@ public partial class JpegDecoderTests image.DebugSave(provider); image.CompareToOriginal(provider); } - - [Theory] - [WithFile(TestImages.Jpeg.Issues.Issue2067_CommentMarker, PixelTypes.Rgba32)] - public void JpegDecoder_DecodeMetadataComment(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - string expectedComment = "TEST COMMENT"; - using Image image = provider.GetImage(JpegDecoder.Instance); - JpegMetadata metadata = image.Metadata.GetJpegMetadata(); - - Assert.Equal(1, metadata.Comments?.Count); - Assert.Equal(expectedComment, metadata.GetComments()?.FirstOrDefault()); - image.DebugSave(provider); - image.CompareToOriginal(provider); - } } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index 50f47a1345..fa54859a36 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -184,8 +184,8 @@ public partial class JpegEncoderTests using var memStream = new MemoryStream(); // act - meta.SaveComment("First comment"); - meta.SaveComment("Second Comment"); + meta.SetComment(0, "First comment"); + meta.SetComment(1, "Second Comment"); input.Save(memStream, JpegEncoder); // assert @@ -193,9 +193,9 @@ public partial class JpegEncoderTests using var output = Image.Load(memStream); JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); - Assert.Equal(2, actual.Comments.Count); - Assert.Equal(meta.Comments.ElementAt(0).ToString(), actual.Comments.ElementAt(0).ToString()); - Assert.Equal(meta.Comments.ElementAt(1).ToString(), actual.Comments.ElementAt(1).ToString()); + Assert.Equal(2, actual.Comments?.Count); + Assert.Equal(meta.Comments?.ElementAt(0).ToString(), actual.Comments?.ElementAt(0).ToString()); + Assert.Equal(meta.Comments?.ElementAt(1).ToString(), actual.Comments?.ElementAt(1).ToString()); } [Theory] From d6165909fd7be5e45b2f176373dd9694e1ab93e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Sun, 7 Jan 2024 20:13:19 +0100 Subject: [PATCH 118/219] tab --- tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 901bb4619a..8b991228b4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -56,7 +56,7 @@ public class JpegMetadataTests var meta = new JpegMetadata { LuminanceQuality = qualityLuma, ChrominanceQuality = qualityChroma }; - Assert.Equal(meta.Quality, qualityLuma); + Assert.Equal(meta.Quality, qualityLuma); } [Fact] From 84a7988f5d60434e90c496493fe060ea91b81911 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Mon, 8 Jan 2024 18:43:06 +0100 Subject: [PATCH 119/219] TrueColor images with 32 bits per pixel are assumed to always have 8 bit alpha channel --- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 8 +++++++- src/ImageSharp/Formats/Tga/TgaFileHeader.cs | 5 +---- 2 files changed, 8 insertions(+), 5 deletions(-) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 26e057bff9..eb0e508cd9 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -937,7 +937,9 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals this.tgaMetadata = this.metadata.GetTgaMetadata(); this.tgaMetadata.BitsPerPixel = (TgaBitsPerPixel)this.fileHeader.PixelDepth; - int alphaBits = this.fileHeader.ImageDescriptor & 0xf; + // TrueColor images with 32 bits per pixel are assumed to always have 8 bit alpha channel, + // because some encoders do not set correctly the alpha bits in the image descriptor. + int alphaBits = this.IsTrueColor32BitPerPixel(this.tgaMetadata.BitsPerPixel) ? 8 : this.fileHeader.ImageDescriptor & 0xf; if (alphaBits is not 0 and not 1 and not 8) { TgaThrowHelper.ThrowInvalidImageContentException("Invalid alpha channel bits"); @@ -949,4 +951,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals // Bits 4 and 5 describe the image origin. return (TgaImageOrigin)((this.fileHeader.ImageDescriptor & 0x30) >> 4); } + + private bool IsTrueColor32BitPerPixel(TgaBitsPerPixel bitsPerPixel) => bitsPerPixel == TgaBitsPerPixel.Pixel32 && + (this.fileHeader.ImageType == TgaImageType.TrueColor || + this.fileHeader.ImageType == TgaImageType.RleTrueColor); } diff --git a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs index 007dc03de1..2613cd610a 100644 --- a/src/ImageSharp/Formats/Tga/TgaFileHeader.cs +++ b/src/ImageSharp/Formats/Tga/TgaFileHeader.cs @@ -131,10 +131,7 @@ internal readonly struct TgaFileHeader /// public byte ImageDescriptor { get; } - public static TgaFileHeader Parse(Span data) - { - return MemoryMarshal.Cast(data)[0]; - } + public static TgaFileHeader Parse(Span data) => MemoryMarshal.Cast(data)[0]; public void WriteTo(Span buffer) { From 1c2bfd8ebfbbb76793678732ea6ad094889f3d80 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Thu, 11 Jan 2024 19:21:54 +0100 Subject: [PATCH 120/219] Add test for issue 2629 --- .../Formats/Tga/TgaDecoderTests.cs | 16 ++++++++++++++-- tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Tga/issues/Issue2629.tga | 3 +++ 3 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Tga/issues/Issue2629.tga diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index da5de8e898..9efbac6a30 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Runtime.InteropServices; using System.Runtime.Intrinsics.X86; using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; @@ -724,7 +723,7 @@ public class TgaDecoderTests { using (Image image = provider.GetImage(TgaDecoder.Instance)) { - // Using here the reference output instead of the the reference decoder, + // Using here the reference output instead of the reference decoder, // because the reference decoder does not ignore the alpha data here. image.DebugSave(provider); image.CompareToReferenceOutput(ImageComparer.Exact, provider); @@ -771,6 +770,19 @@ public class TgaDecoderTests appendPixelTypeToFileName: false); } + // https://github.com/SixLabors/ImageSharp/issues/2629 + [Theory] + [WithFile(Issue2629, PixelTypes.Rgba32)] + public void TgaDecoder_CanDecode_Issue2629(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using (Image image = provider.GetImage(TgaDecoder.Instance)) + { + image.DebugSave(provider); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); + } + } + [Theory] [WithFile(Bit16BottomLeft, PixelTypes.Rgba32)] [WithFile(Bit24BottomLeft, PixelTypes.Rgba32)] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8aa95d3496..65ef95e9da 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -617,6 +617,8 @@ public static class TestImages public const string Github_RLE_legacy = "Tga/Github_RLE_legacy.tga"; public const string WhiteStripesPattern = "Tga/whitestripes.png"; + + public const string Issue2629 = "Tga/issues/Issue2629.tga"; } public static class Webp diff --git a/tests/Images/Input/Tga/issues/Issue2629.tga b/tests/Images/Input/Tga/issues/Issue2629.tga new file mode 100644 index 0000000000..4c87196ad5 --- /dev/null +++ b/tests/Images/Input/Tga/issues/Issue2629.tga @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:defc1396481f426a74e8af51ed57f65cbed932f932673ce5a87fa12ea9b460f8 +size 32786 From 3969525d2ae9ee89055ab220528d1423da156b60 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Jan 2024 10:13:44 +1000 Subject: [PATCH 121/219] Port shuffle4 --- src/ImageSharp/Common/Helpers/Numerics.cs | 7 +- .../Helpers/Shuffle/IComponentShuffle.cs | 77 +++-- .../Common/Helpers/Shuffle/IPad3Shuffle4.cs | 8 +- .../Common/Helpers/Shuffle/IShuffle3.cs | 4 +- .../Common/Helpers/Shuffle/IShuffle4Slice3.cs | 8 +- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 264 +++++++++++------- .../Common/Helpers/SimdUtils.Shuffle.cs | 125 +++++---- .../Formats/Webp/BitWriter/BitWriterBase.cs | 1 - .../Webp/Chunks/WebpAnimationParameter.cs | 1 - .../Formats/Webp/Chunks/WebpFrameData.cs | 2 - .../Formats/Webp/Chunks/WebpVp8X.cs | 2 - .../Formats/Webp/Lossless/Vp8LEncoder.cs | 1 - .../Formats/Webp/Lossy/Vp8Encoder.cs | 1 - .../Helpers => Formats/Webp}/RiffHelper.cs | 2 +- .../Utils/Vector4Converters.RgbaCompatible.cs | 18 +- 15 files changed, 302 insertions(+), 219 deletions(-) rename src/ImageSharp/{Common/Helpers => Formats/Webp}/RiffHelper.cs (98%) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 293997c4de..ca28a7aab5 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -5,7 +5,6 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp; @@ -61,6 +60,12 @@ internal static class Numerics [MethodImpl(MethodImplOptions.AggressiveInlining)] public static nint Modulo4(nint x) => x & 3; + /// + /// Calculates % 4 + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static nuint Modulo4(nuint x) => x & 3; + /// /// Calculates % 8 /// diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index 683ac518b8..d4ab8c6183 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -19,24 +19,26 @@ namespace SixLabors.ImageSharp; internal interface IComponentShuffle { /// - /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffles then slices 8-bit integers in + /// using the control and store the results in . + /// If successful, this method will reduce the length of length + /// by the shuffle amount. /// /// The source span of bytes. - /// The destination span of bytes. - void ShuffleReduce(ref ReadOnlySpan source, ref Span dest); + /// The destination span of bytes. + void ShuffleReduce(ref ReadOnlySpan source, ref Span destination); /// - /// Shuffle 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffle 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// - /// Implementation can assume that source.Length is less or equal than dest.Length. + /// Implementation can assume that source.Length is less or equal than destination.Length. /// Loops should iterate using source.Length. /// - void RunFallbackShuffle(ReadOnlySpan source, Span dest); + void Shuffle(ReadOnlySpan source, Span destination); } /// @@ -44,24 +46,21 @@ internal interface IShuffle4 : IComponentShuffle { } -internal readonly struct DefaultShuffle4 : IShuffle4 +internal readonly struct DefaultShuffle4(byte control) : IShuffle4 { - public DefaultShuffle4(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); - Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); for (nuint i = 0; i < (uint)source.Length; i += 4) { @@ -76,14 +75,14 @@ internal readonly struct DefaultShuffle4 : IShuffle4 internal readonly struct WXYZShuffle4 : IShuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle2103); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); uint n = (uint)source.Length / 4; for (nuint i = 0; i < n; i++) @@ -100,14 +99,14 @@ internal readonly struct WXYZShuffle4 : IShuffle4 internal readonly struct WZYXShuffle4 : IShuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0123); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); uint n = (uint)source.Length / 4; for (nuint i = 0; i < n; i++) @@ -124,14 +123,14 @@ internal readonly struct WZYXShuffle4 : IShuffle4 internal readonly struct YZWXShuffle4 : IShuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle0321); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); uint n = (uint)source.Length / 4; for (nuint i = 0; i < n; i++) @@ -148,14 +147,14 @@ internal readonly struct YZWXShuffle4 : IShuffle4 internal readonly struct ZYXWShuffle4 : IShuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3012); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); uint n = (uint)source.Length / 4; for (nuint i = 0; i < n; i++) @@ -179,14 +178,14 @@ internal readonly struct ZYXWShuffle4 : IShuffle4 internal readonly struct XWZYShuffle4 : IShuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle1230); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); uint n = (uint)source.Length / 4; for (nuint i = 0; i < n; i++) diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs index 6cf6eef08e..255448d619 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs @@ -24,12 +24,12 @@ internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4 => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, this.Control); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte dBase = ref MemoryMarshal.GetReference(dest); - Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); Span temp = stackalloc byte[4]; ref byte t = ref MemoryMarshal.GetReference(temp); @@ -52,10 +52,10 @@ internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4 { [MethodImpl(InliningOptions.ShortMethod)] public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, Shuffle.MMShuffle3210); + => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte dBase = ref MemoryMarshal.GetReference(dest); diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs index 2cd586212e..89faca2437 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs @@ -24,12 +24,12 @@ internal readonly struct DefaultShuffle3 : IShuffle3 => HwIntrinsics.Shuffle3Reduce(ref source, ref dest, this.Control); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte dBase = ref MemoryMarshal.GetReference(dest); - Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); for (nuint i = 0; i < (uint)source.Length; i += 3) { diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs index 5e82973e33..30fda7a8e1 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs @@ -24,12 +24,12 @@ internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3 => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, this.Control); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span dest) { ref byte sBase = ref MemoryMarshal.GetReference(source); ref byte dBase = ref MemoryMarshal.GetReference(dest); - Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4) { @@ -44,10 +44,10 @@ internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3 { [MethodImpl(InliningOptions.ShortMethod)] public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, Shuffle.MMShuffle3210); + => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void RunFallbackShuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span dest) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index ad079b52e9..4732effd4a 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -51,22 +51,32 @@ internal static partial class SimdUtils /// /// Shuffle single-precision (32-bit) floating-point elements in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of floats. - /// The destination span of floats. + /// The destination span of floats. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, + ref Span destination, [ConstantExpected] byte control) { - if (Avx.IsSupported || Sse.IsSupported) + if (Vector512.IsHardwareAccelerated || Vector256.IsHardwareAccelerated || Vector128.IsHardwareAccelerated) { - int remainder = Avx.IsSupported - ? Numerics.ModuloP2(source.Length, Vector256.Count) - : Numerics.ModuloP2(source.Length, Vector128.Count); + int remainder = 0; + if (Vector512.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Vector256.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector256.Count); + } + else if (Vector128.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector128.Count); + } int adjustedCount = source.Length - remainder; @@ -74,17 +84,17 @@ internal static partial class SimdUtils { Shuffle4( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } /// - /// Shuffle 8-bit integers within 128-bit lanes in + /// Shuffle 8-bit integers /// using the control and store the results in . /// /// The source span of bytes. @@ -96,11 +106,21 @@ internal static partial class SimdUtils ref Span dest, byte control) { - if (Avx2.IsSupported || Ssse3.IsSupported) + if (Vector512.IsHardwareAccelerated || Vector256.IsHardwareAccelerated || Vector128.IsHardwareAccelerated) { - int remainder = Avx2.IsSupported - ? Numerics.ModuloP2(source.Length, Vector256.Count) - : Numerics.ModuloP2(source.Length, Vector128.Count); + int remainder = 0; + if (Vector512.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Vector256.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector256.Count); + } + else if (Vector128.IsHardwareAccelerated) + { + remainder = Numerics.ModuloP2(source.Length, Vector128.Count); + } int adjustedCount = source.Length - remainder; @@ -218,76 +238,102 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, [ConstantExpected] byte control) { - if (Avx.IsSupported) + if (Vector512.IsHardwareAccelerated) { - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + Span temp = stackalloc int[Vector512.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector512 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - nint n = (nint)dest.Vector256Count(); - nint m = Numerics.Modulo4(n); - nint u = n - m; + nuint n = (uint)destination.Length / (uint)Vector512.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { - ref Vector256 vd0 = ref Unsafe.Add(ref destBase, i); - ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Avx.Permute(vs0, control); - Unsafe.Add(ref vd0, 1) = Avx.Permute(Unsafe.Add(ref vs0, 1), control); - Unsafe.Add(ref vd0, 2) = Avx.Permute(Unsafe.Add(ref vs0, 2), control); - Unsafe.Add(ref vd0, 3) = Avx.Permute(Unsafe.Add(ref vs0, 3), control); + vd0 = Vector512.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Avx.Permute(Unsafe.Add(ref sourceBase, i), control); + Unsafe.Add(ref destinationBase, i) = Vector512.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } - else + else if (Vector256.IsHardwareAccelerated) { - // Sse - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + Span temp = stackalloc int[Vector256.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector256 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - nint n = (nint)((uint)dest.Length / (uint)Vector128.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; + nuint n = (uint)destination.Length / (uint)Vector256.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { - ref Vector128 vd0 = ref Unsafe.Add(ref destBase, i); - ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Sse.Shuffle(vs0, vs0, control); + vd0 = Vector256.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + } - Vector128 vs1 = Unsafe.Add(ref vs0, 1); - Unsafe.Add(ref vd0, 1) = Sse.Shuffle(vs1, vs1, control); + if (m > 0) + { + for (nuint i = u; i < n; i++) + { + Unsafe.Add(ref destinationBase, i) = Vector256.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + } + } + } + else if (Vector128.IsHardwareAccelerated) + { + Span temp = stackalloc int[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); + + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - Vector128 vs2 = Unsafe.Add(ref vs0, 2); - Unsafe.Add(ref vd0, 2) = Sse.Shuffle(vs2, vs2, control); + nuint n = (uint)destination.Length / (uint)Vector128.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; + + for (nuint i = 0; i < u; i += 4) + { + ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); - Vector128 vs3 = Unsafe.Add(ref vs0, 3); - Unsafe.Add(ref vd0, 3) = Sse.Shuffle(vs3, vs3, control); + vd0 = Vector128.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Vector128 vs = Unsafe.Add(ref sourceBase, i); - Unsafe.Add(ref destBase, i) = Sse.Shuffle(vs, vs, control); + Unsafe.Add(ref destinationBase, i) = Vector128.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } @@ -296,80 +342,102 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, byte control) { - if (Avx2.IsSupported) + if (Vector512.IsHardwareAccelerated) { - // I've chosen to do this for convenience while we determine what - // shuffle controls to add to the library. - // We can add static ROS instances if need be in the future. - Span bytes = stackalloc byte[Vector256.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector256 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector512.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector512 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + nuint n = (uint)destination.Length / (uint)Vector512.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; + + for (nuint i = 0; i < u; i += 4) + { + ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); + ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); + + vd0 = Vector512.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + } + + if (m > 0) + { + for (nuint i = u; i < n; i++) + { + Unsafe.Add(ref destinationBase, i) = Vector512.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + } + } + } + else if (Vector256.IsHardwareAccelerated) + { + Span temp = stackalloc byte[Vector256.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector256 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - nint n = (nint)((uint)dest.Length / (uint)Vector256.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - for (nint i = 0; i < u; i += 4) + nuint n = (uint)destination.Length / (uint)Vector256.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; + + for (nuint i = 0; i < u; i += 4) { ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); - ref Vector256 vd0 = ref Unsafe.Add(ref destBase, i); + ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Avx2.Shuffle(vs0, vshuffle); - Unsafe.Add(ref vd0, 1) = Avx2.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle); - Unsafe.Add(ref vd0, 2) = Avx2.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle); - Unsafe.Add(ref vd0, 3) = Avx2.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle); + vd0 = Vector256.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Avx2.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); + Unsafe.Add(ref destinationBase, i) = Vector256.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } - else + else if (Vector128.IsHardwareAccelerated) { - // Ssse3 - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); - - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - nint n = (nint)((uint)dest.Length / (uint)Vector128.Count); - nint m = Numerics.Modulo4(n); - nint u = n - m; + nuint n = (uint)destination.Length / (uint)Vector128.Count; + nuint m = Numerics.Modulo4(n); + nuint u = n - m; - for (nint i = 0; i < u; i += 4) + for (nuint i = 0; i < u; i += 4) { ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); - ref Vector128 vd0 = ref Unsafe.Add(ref destBase, i); + ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Ssse3.Shuffle(vs0, vshuffle); - Unsafe.Add(ref vd0, 1) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 1), vshuffle); - Unsafe.Add(ref vd0, 2) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 2), vshuffle); - Unsafe.Add(ref vd0, 3) = Ssse3.Shuffle(Unsafe.Add(ref vs0, 3), vshuffle); + vd0 = Vector128.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { - for (nint i = u; i < n; i++) + for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destBase, i) = Ssse3.Shuffle(Unsafe.Add(ref sourceBase, i), vshuffle); + Unsafe.Add(ref destinationBase, i) = Vector128.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs index 83cd3d246c..dbeb54a80c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Shuffle.cs @@ -12,140 +12,140 @@ internal static partial class SimdUtils { /// /// Shuffle single-precision (32-bit) floating-point elements in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of floats. - /// The destination span of floats. + /// The destination span of floats. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, [ConstantExpected] byte control) { - VerifyShuffle4SpanInput(source, dest); + VerifyShuffle4SpanInput(source, destination); - HwIntrinsics.Shuffle4Reduce(ref source, ref dest, control); + HwIntrinsics.Shuffle4Reduce(ref source, ref destination, control); // Deal with the remainder: if (source.Length > 0) { - Shuffle4Remainder(source, dest, control); + Shuffle4Remainder(source, destination, control); } } /// /// Shuffle 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle4 { - VerifyShuffle4SpanInput(source, dest); + VerifyShuffle4SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Shuffle 8-bit integer triplets within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle3( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle3 { - // Source length should be smaller than dest length, and divisible by 3. - VerifyShuffle3SpanInput(source, dest); + // Source length should be smaller than destination length, and divisible by 3. + VerifyShuffle3SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Pads then shuffles 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Pad3Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IPad3Shuffle4 { - VerifyPad3Shuffle4SpanInput(source, dest); + VerifyPad3Shuffle4SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } /// /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The type of shuffle struct. /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The type of shuffle to perform. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Slice3( ReadOnlySpan source, - Span dest, + Span destination, TShuffle shuffle) where TShuffle : struct, IShuffle4Slice3 { - VerifyShuffle4Slice3SpanInput(source, dest); + VerifyShuffle4Slice3SpanInput(source, destination); - shuffle.ShuffleReduce(ref source, ref dest); + shuffle.ShuffleReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - shuffle.RunFallbackShuffle(source, dest); + shuffle.Shuffle(source, destination); } } private static void Shuffle4Remainder( ReadOnlySpan source, - Span dest, + Span destination, byte control) { ref float sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); + ref float dBase = ref MemoryMarshal.GetReference(destination); Shuffle.InverseMMShuffle(control, out uint p3, out uint p2, out uint p1, out uint p0); for (nuint i = 0; i < (uint)source.Length; i += 4) @@ -158,69 +158,69 @@ internal static partial class SimdUtils } [Conditional("DEBUG")] - internal static void VerifyShuffle4SpanInput(ReadOnlySpan source, Span dest) + internal static void VerifyShuffle4SpanInput(ReadOnlySpan source, Span destination) where T : struct { DebugGuard.IsTrue( - source.Length == dest.Length, + source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( source.Length % 4 == 0, nameof(source), - "Input spans must be divisable by 4!"); + "Input spans must be divisible by 4!"); } [Conditional("DEBUG")] - private static void VerifyShuffle3SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyShuffle3SpanInput(ReadOnlySpan source, Span destination) where T : struct { DebugGuard.IsTrue( - source.Length <= dest.Length, + source.Length <= destination.Length, nameof(source), - "Source should fit into dest!"); + "Source should fit into destination!"); DebugGuard.IsTrue( source.Length % 3 == 0, nameof(source), - "Input spans must be divisable by 3!"); + "Input spans must be divisible by 3!"); } [Conditional("DEBUG")] - private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyPad3Shuffle4SpanInput(ReadOnlySpan source, Span destination) { DebugGuard.IsTrue( source.Length % 3 == 0, nameof(source), - "Input span must be divisable by 3!"); + "Input span must be divisible by 3!"); DebugGuard.IsTrue( - dest.Length % 4 == 0, - nameof(dest), - "Output span must be divisable by 4!"); + destination.Length % 4 == 0, + nameof(destination), + "Output span must be divisible by 4!"); DebugGuard.IsTrue( - source.Length == dest.Length * 3 / 4, + source.Length == destination.Length * 3 / 4, nameof(source), "Input span must be 3/4 the length of the output span!"); } [Conditional("DEBUG")] - private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan source, Span dest) + private static void VerifyShuffle4Slice3SpanInput(ReadOnlySpan source, Span destination) { DebugGuard.IsTrue( source.Length % 4 == 0, nameof(source), - "Input span must be divisable by 4!"); + "Input span must be divisible by 4!"); DebugGuard.IsTrue( - dest.Length % 3 == 0, - nameof(dest), - "Output span must be divisable by 3!"); + destination.Length % 3 == 0, + nameof(destination), + "Output span must be divisible by 3!"); DebugGuard.IsTrue( - dest.Length >= source.Length * 3 / 4, + destination.Length >= source.Length * 3 / 4, nameof(source), "Output span must be at least 3/4 the length of the input span!"); } @@ -509,6 +509,27 @@ internal static partial class SimdUtils } } + [MethodImpl(InliningOptions.ShortMethod)] + public static void MMShuffleSpan(ref Span span, byte control) + { + InverseMMShuffle( + control, + out uint p3, + out uint p2, + out uint p1, + out uint p0); + + ref int spanBase = ref MemoryMarshal.GetReference(span); + + for (nuint i = 0; i < (uint)span.Length; i += 4) + { + Unsafe.Add(ref spanBase, i + 0) = (int)(p0 + i); + Unsafe.Add(ref spanBase, i + 1) = (int)(p1 + i); + Unsafe.Add(ref spanBase, i + 2) = (int)(p2 + i); + Unsafe.Add(ref spanBase, i + 3) = (int)(p3 + i); + } + } + [MethodImpl(InliningOptions.ShortMethod)] public static void InverseMMShuffle( byte control, diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index c98be1fcd8..9279926869 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Metadata.Profiles.Exif; using SixLabors.ImageSharp.Metadata.Profiles.Icc; diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs index 3855a293c1..cff9f47afa 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpAnimationParameter.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; -using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Webp.Chunks; diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs index 5ed7aab1ea..c8ff579a89 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpFrameData.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; - namespace SixLabors.ImageSharp.Formats.Webp.Chunks; internal readonly struct WebpFrameData diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index 70d6870ce4..f781d6114d 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Common.Helpers; - namespace SixLabors.ImageSharp.Formats.Webp.Chunks; internal readonly struct WebpVp8X diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 518c09ff4d..f15cb3eb58 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -6,7 +6,6 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 2b74c300a4..6e9e4f9cd0 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -4,7 +4,6 @@ using System.Buffers; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitWriter; using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Memory; diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Formats/Webp/RiffHelper.cs similarity index 98% rename from src/ImageSharp/Common/Helpers/RiffHelper.cs rename to src/ImageSharp/Formats/Webp/RiffHelper.cs index 8f06e5886f..d3862ea8b7 100644 --- a/src/ImageSharp/Common/Helpers/RiffHelper.cs +++ b/src/ImageSharp/Formats/Webp/RiffHelper.cs @@ -4,7 +4,7 @@ using System.Buffers.Binary; using System.Text; -namespace SixLabors.ImageSharp.Common.Helpers; +namespace SixLabors.ImageSharp.Formats.Webp; internal static class RiffHelper { diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 3442a08075..8616ecb3b1 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -28,7 +28,7 @@ internal static partial class Vector4Converters private static readonly int Vector4ConversionThreshold = CalculateVector4ConversionThreshold(); /// - /// Provides an efficient default implementation for + /// Provides an efficient default implementation for /// The method works by internally converting to a therefore it's not applicable for that type! /// [MethodImpl(InliningOptions.ShortMethod)] @@ -72,7 +72,7 @@ internal static partial class Vector4Converters } /// - /// Provides an efficient default implementation for + /// Provides an efficient default implementation for /// The method is works by internally converting to a therefore it's not applicable for that type! /// [MethodImpl(InliningOptions.ShortMethod)] @@ -102,16 +102,14 @@ internal static partial class Vector4Converters // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: - using (IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count)) - { - Span tempSpan = tempBuffer.Memory.Span; + using IMemoryOwner tempBuffer = configuration.MemoryAllocator.Allocate(count); + Span tempSpan = tempBuffer.Memory.Span; - SimdUtils.NormalizedFloatToByteSaturate( - MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(tempSpan)); + SimdUtils.NormalizedFloatToByteSaturate( + MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(tempSpan)); - pixelOperations.FromRgba32(configuration, tempSpan, destPixels); - } + pixelOperations.FromRgba32(configuration, tempSpan, destPixels); } private static int CalculateVector4ConversionThreshold() From 4931372733a618bc32f382a05c7231dbafb1b3a1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 13 Jan 2024 15:43:26 +1000 Subject: [PATCH 122/219] Port first Shuffl3 method --- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 88 ++++++++--------- .../Common/Helpers/Vector128Utilities.cs | 99 +++++++++++++++++++ 2 files changed, 142 insertions(+), 45 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/Vector128Utilities.cs diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 4732effd4a..4b9a90a952 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -8,6 +8,7 @@ using System.Runtime.InteropServices; using System.Runtime.Intrinsics; using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp; @@ -95,15 +96,15 @@ internal static partial class SimdUtils /// /// Shuffle 8-bit integers - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, + ref Span destination, byte control) { if (Vector512.IsHardwareAccelerated || Vector256.IsHardwareAccelerated || Vector128.IsHardwareAccelerated) @@ -128,29 +129,29 @@ internal static partial class SimdUtils { Shuffle4( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } /// /// Shuffles 8-bit integer triplets within 128-bit lanes in - /// using the control and store the results in . + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle3Reduce( ref ReadOnlySpan source, - ref Span dest, + ref Span destination, byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsRightShift) { int remainder = source.Length % (Vector128.Count * 3); @@ -160,11 +161,11 @@ internal static partial class SimdUtils { Shuffle3( source[..adjustedCount], - dest[..adjustedCount], + destination[..adjustedCount], control); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } @@ -446,24 +447,21 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle3( ReadOnlySpan source, - Span dest, + Span destination, byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsRightShift) { - Vector128 vmask = ShuffleMaskPad4Nx16(); - Vector128 vmasko = ShuffleMaskSlice4Nx16(); - Vector128 vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); + Vector128 maskPad4Nx16 = ShuffleMaskPad4Nx16(); + Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); + Vector128 maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); Span bytes = stackalloc byte[Vector128.Count]; Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -472,36 +470,36 @@ internal static partial class SimdUtils ref Vector128 vs = ref Unsafe.Add(ref sourceBase, i); Vector128 v0 = vs; - Vector128 v1 = Unsafe.Add(ref vs, 1); - Vector128 v2 = Unsafe.Add(ref vs, 2); - Vector128 v3 = Sse2.ShiftRightLogical128BitLane(v2, 4); + Vector128 v1 = Unsafe.Add(ref vs, (nuint)1); + Vector128 v2 = Unsafe.Add(ref vs, (nuint)2); + Vector128 v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v2 = Ssse3.AlignRight(v2, v1, 8); - v1 = Ssse3.AlignRight(v1, v0, 12); + v2 = Vector128Utilities.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v1, v0, 12); - v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vmask), vshuffle); - v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vmask), vshuffle); - v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vmask), vshuffle); - v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vmask), vshuffle); + v0 = Vector128.Shuffle(Vector128.Shuffle(v0, maskPad4Nx16), mask); + v1 = Vector128.Shuffle(Vector128.Shuffle(v1, maskPad4Nx16), mask); + v2 = Vector128.Shuffle(Vector128.Shuffle(v2, maskPad4Nx16), mask); + v3 = Vector128.Shuffle(Vector128.Shuffle(v3, maskPad4Nx16), mask); - v0 = Ssse3.Shuffle(v0, vmaske); - v1 = Ssse3.Shuffle(v1, vmasko); - v2 = Ssse3.Shuffle(v2, vmaske); - v3 = Ssse3.Shuffle(v3, vmasko); + v0 = Vector128.Shuffle(v0, maskE); + v1 = Vector128.Shuffle(v1, maskSlice4Nx16); + v2 = Vector128.Shuffle(v2, maskE); + v3 = Vector128.Shuffle(v3, maskSlice4Nx16); - v0 = Ssse3.AlignRight(v1, v0, 4); - v3 = Ssse3.AlignRight(v3, v2, 12); + v0 = Vector128Utilities.AlignRight(v1, v0, 4); + v3 = Vector128Utilities.AlignRight(v3, v2, 12); - v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4); - v2 = Sse2.ShiftRightLogical128BitLane(v2, 4); + v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4); + v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v1 = Ssse3.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v2, v1, 8); - ref Vector128 vd = ref Unsafe.Add(ref destBase, i); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, i); vd = v0; - Unsafe.Add(ref vd, 1) = v1; - Unsafe.Add(ref vd, 2) = v3; + Unsafe.Add(ref vd, (nuint)1) = v1; + Unsafe.Add(ref vd, (nuint)2) = v3; } } } @@ -509,7 +507,7 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ShortMethod)] private static void Pad3Shuffle4( ReadOnlySpan source, - Span dest, + Span destination, byte control) { if (Ssse3.IsSupported) @@ -525,7 +523,7 @@ internal static partial class SimdUtils ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs new file mode 100644 index 0000000000..829362da88 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -0,0 +1,99 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have not yet been normalized in the runtime. +/// Should only be used if the intrinsics are available. +/// +internal static class Vector128Utilities +{ + /// + /// Gets a value indicating whether right shift operations are supported. + /// + public static bool SupportsRightShift + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Ssse3.IsSupported || AdvSimd.IsSupported; + } + + /// + /// Shifts a 128-bit value right by a specified number of bytes while shifting in zeros. + /// + /// The value to shift. + /// The number of bytes to shift by. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ShiftRightBytesInVector(Vector128 value, [ConstantExpected(Max = (byte)15)] byte numBytes) + { + if (Sse2.IsSupported) + { + return Sse2.ShiftRightLogical128BitLane(value, numBytes); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(value, Vector128.Zero, numBytes); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Shifts a 128-bit value left by a specified number of bytes while shifting in zeros. + /// + /// The value to shift. + /// The number of bytes to shift by. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ShiftLeftBytesInVector(Vector128 value, [ConstantExpected(Max = (byte)15)] byte numBytes) + { + if (Sse2.IsSupported) + { + return Sse2.ShiftLeftLogical128BitLane(value, numBytes); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(Vector128.Zero, value, numBytes); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Right aligns elements of two source 128-bit values depending on bits in a mask. + /// + /// The left hand source vector. + /// The right hand source vector. + /// An 8-bit mask used for the operation. + /// The . + public static Vector128 AlignRight(Vector128 left, Vector128 right, [ConstantExpected(Max = (byte)15)] byte mask) + { + if (Sse3.IsSupported) + { + return Ssse3.AlignRight(left, right, mask); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractVector128(right, left, mask); + } + + ThrowUnreachableException(); + return default; + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} From ce73c49fcba4c0411d717887d6644998d30f4016 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sat, 13 Jan 2024 19:14:05 +0100 Subject: [PATCH 123/219] Update 32 bit test images without alpha bits --- tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs | 4 +--- tests/Images/Input/Tga/32bit_no_alphabits.tga | 4 ++-- tests/Images/Input/Tga/32bit_rle_no_alphabits.tga | 4 ++-- 3 files changed, 5 insertions(+), 7 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs index 9efbac6a30..dbd7885e52 100644 --- a/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Tga/TgaDecoderTests.cs @@ -723,10 +723,8 @@ public class TgaDecoderTests { using (Image image = provider.GetImage(TgaDecoder.Instance)) { - // Using here the reference output instead of the reference decoder, - // because the reference decoder does not ignore the alpha data here. image.DebugSave(provider); - image.CompareToReferenceOutput(ImageComparer.Exact, provider); + ImageComparingUtils.CompareWithReferenceDecoder(provider, image); } } diff --git a/tests/Images/Input/Tga/32bit_no_alphabits.tga b/tests/Images/Input/Tga/32bit_no_alphabits.tga index 903eca4594..206e8d7c5e 100644 --- a/tests/Images/Input/Tga/32bit_no_alphabits.tga +++ b/tests/Images/Input/Tga/32bit_no_alphabits.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:0aea1128a1bd7477dfa0d007a1eba25907be24847284c48a5f9fbd61bcea3cf0 -size 61522 +oid sha256:019315f9dcbe4516ecb15426a45c210d437e9ad152c8e1a0e80abe9449177e12 +size 235218 diff --git a/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga b/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga index b21dad5e0d..153b0a055b 100644 --- a/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga +++ b/tests/Images/Input/Tga/32bit_rle_no_alphabits.tga @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:98a198392bd527523f8649d6126af81e5a588ad7265dc3d48a1da7b5a6cb6ff7 -size 230578 +oid sha256:33954ae93b4c7d57f52965a9028e97119c546db1da255100c2903a2760c7479e +size 76870 From 10b27a3e29d80311648964887af2d6d0dcdd5454 Mon Sep 17 00:00:00 2001 From: Brian Popow Date: Sun, 14 Jan 2024 10:36:22 +0100 Subject: [PATCH 124/219] Remove no longer needed 32 bit tga reference images --- ...CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png | 3 --- ...ecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png | 3 --- 2 files changed, 6 deletions(-) delete mode 100644 tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png delete mode 100644 tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png diff --git a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png b/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png deleted file mode 100644 index e12985f7ae..0000000000 --- a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_no_alphabits.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:d3dc0516f656c14b5ffcc40f88d3912f2a8fb310dfbda5836e15847e205919b5 -size 1012 diff --git a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png b/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png deleted file mode 100644 index 726721824e..0000000000 --- a/tests/Images/External/ReferenceOutput/TgaDecoderTests/TgaDecoder_CanDecode_WhenAlphaBitsNotSet_Rgba32_32bit_rle_no_alphabits.png +++ /dev/null @@ -1,3 +0,0 @@ -version https://git-lfs.github.com/spec/v1 -oid sha256:cad24c7e4657f2bc8d8a60ea76397eac0adf8dee5fc81f60bc5bc02dd7eeed8f -size 90589 From b250ac3923c86868e1a1694054825bc66c2b1553 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Jan 2024 14:30:16 +1000 Subject: [PATCH 125/219] Introduce new utilities to replace poor performing runtime methods --- .../Helpers/Shuffle/IComponentShuffle.cs | 173 +------------ .../Common/Helpers/Shuffle/IPad3Shuffle4.cs | 26 +- .../Common/Helpers/Shuffle/IShuffle3.cs | 18 +- .../Common/Helpers/Shuffle/IShuffle4.cs | 178 ++++++++++++++ .../Common/Helpers/Shuffle/IShuffle4Slice3.cs | 28 +-- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 230 +++++++++--------- .../Common/Helpers/Vector128Utilities.cs | 83 ++++++- .../Common/Helpers/Vector256Utilities.cs | 78 ++++++ .../Common/Helpers/Vector512Utilities.cs | 80 ++++++ 9 files changed, 563 insertions(+), 331 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs create mode 100644 src/ImageSharp/Common/Helpers/Vector256Utilities.cs create mode 100644 src/ImageSharp/Common/Helpers/Vector512Utilities.cs diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs index d4ab8c6183..c856267db2 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IComponentShuffle.cs @@ -1,12 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; -using static SixLabors.ImageSharp.SimdUtils; - // The JIT can detect and optimize rotation idioms ROTL (Rotate Left) // and ROTR (Rotate Right) emitting efficient CPU instructions: // https://github.com/dotnet/coreclr/pull/1830 @@ -20,7 +14,7 @@ internal interface IComponentShuffle { /// /// Shuffles then slices 8-bit integers in - /// using the control and store the results in . + /// using a byte control and store the results in . /// If successful, this method will reduce the length of length /// by the shuffle amount. /// @@ -40,168 +34,3 @@ internal interface IComponentShuffle /// void Shuffle(ReadOnlySpan source, Span destination); } - -/// -internal interface IShuffle4 : IComponentShuffle -{ -} - -internal readonly struct DefaultShuffle4(byte control) : IShuffle4 -{ - public byte Control { get; } = control; - - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(destination); - - SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); - - for (nuint i = 0; i < (uint)source.Length; i += 4) - { - Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i); - Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); - Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); - Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); - } - } -} - -internal readonly struct WXYZShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // ROTL(8, packed) = [Z Y X W] - Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); - } - } -} - -internal readonly struct WZYXShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // REVERSE(packedArgb) = [X Y Z W] - Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); - } - } -} - -internal readonly struct YZWXShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // ROTR(8, packedArgb) = [Y Z W X] - Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8); - } - } -} - -internal readonly struct ZYXWShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // tmp1 = [W 0 Y 0] - // tmp2 = [0 Z 0 X] - // tmp3=ROTL(16, tmp2) = [0 X 0 Z] - // tmp1 + tmp3 = [W X Y Z] - uint tmp1 = packed & 0xFF00FF00; - uint tmp2 = packed & 0x00FF00FF; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; - } - } -} - -internal readonly struct XWZYShuffle4 : IShuffle4 -{ - [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) - => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230); - - [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span destination) - { - ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); - uint n = (uint)source.Length / 4; - - for (nuint i = 0; i < n; i++) - { - uint packed = Unsafe.Add(ref sBase, i); - - // packed = [W Z Y X] - // tmp1 = [0 Z 0 X] - // tmp2 = [W 0 Y 0] - // tmp3=ROTL(16, tmp2) = [Y 0 W 0] - // tmp1 + tmp3 = [Y Z W X] - uint tmp1 = packed & 0x00FF00FF; - uint tmp2 = packed & 0xFF00FF00; - uint tmp3 = BitOperations.RotateLeft(tmp2, 16); - - Unsafe.Add(ref dBase, i) = tmp1 + tmp3; - } - } -} diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs index 255448d619..0f282c7f9a 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IPad3Shuffle4.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,22 +13,21 @@ internal interface IPad3Shuffle4 : IComponentShuffle { } -internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4 +internal readonly struct DefaultPad3Shuffle4([ConstantExpected] byte control) : IPad3Shuffle4 { - public DefaultPad3Shuffle4(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); @@ -51,14 +51,14 @@ internal readonly struct DefaultPad3Shuffle4 : IPad3Shuffle4 internal readonly struct XYZWPad3Shuffle4 : IPad3Shuffle4 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref dest, SimdUtils.Shuffle.MMShuffle3210); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Pad3Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); ref byte sEnd = ref Unsafe.Add(ref sBase, (uint)source.Length); ref byte sLoopEnd = ref Unsafe.Subtract(ref sEnd, 4); diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs index 89faca2437..3c0973ad69 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle3.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,22 +13,21 @@ internal interface IShuffle3 : IComponentShuffle { } -internal readonly struct DefaultShuffle3 : IShuffle3 +internal readonly struct DefaultShuffle3([ConstantExpected] byte control) : IShuffle3 { - public DefaultShuffle3(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle3Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle3Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs new file mode 100644 index 0000000000..d5c6df2c8b --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4.cs @@ -0,0 +1,178 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using System.Diagnostics.CodeAnalysis; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using static SixLabors.ImageSharp.SimdUtils; + +namespace SixLabors.ImageSharp; + +/// +internal interface IShuffle4 : IComponentShuffle +{ +} + +internal readonly struct DefaultShuffle4([ConstantExpected] byte control) : IShuffle4 +{ + public byte Control { get; } = control; + + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(destination); + + SimdUtils.Shuffle.InverseMMShuffle(this.Control, out uint p3, out uint p2, out uint p1, out uint p0); + + for (nuint i = 0; i < (uint)source.Length; i += 4) + { + Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + i); + Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + i); + Unsafe.Add(ref dBase, i + 2) = Unsafe.Add(ref sBase, p2 + i); + Unsafe.Add(ref dBase, i + 3) = Unsafe.Add(ref sBase, p3 + i); + } + } +} + +internal readonly struct WXYZShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle2103); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // ROTL(8, packed) = [Z Y X W] + Unsafe.Add(ref dBase, i) = (packed << 8) | (packed >> 24); + } + } +} + +internal readonly struct WZYXShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0123); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // REVERSE(packedArgb) = [X Y Z W] + Unsafe.Add(ref dBase, i) = BinaryPrimitives.ReverseEndianness(packed); + } + } +} + +internal readonly struct YZWXShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle0321); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // ROTR(8, packedArgb) = [Y Z W X] + Unsafe.Add(ref dBase, i) = BitOperations.RotateRight(packed, 8); + } + } +} + +internal readonly struct ZYXWShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3012); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [W 0 Y 0] + // tmp2 = [0 Z 0 X] + // tmp3=ROTL(16, tmp2) = [0 X 0 Z] + // tmp1 + tmp3 = [W X Y Z] + uint tmp1 = packed & 0xFF00FF00; + uint tmp2 = packed & 0x00FF00FF; + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + } + } +} + +internal readonly struct XWZYShuffle4 : IShuffle4 +{ + [MethodImpl(InliningOptions.ShortMethod)] + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle1230); + + [MethodImpl(InliningOptions.ShortMethod)] + public void Shuffle(ReadOnlySpan source, Span destination) + { + ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); + ref uint dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); + uint n = (uint)source.Length / 4; + + for (nuint i = 0; i < n; i++) + { + uint packed = Unsafe.Add(ref sBase, i); + + // packed = [W Z Y X] + // tmp1 = [0 Z 0 X] + // tmp2 = [W 0 Y 0] + // tmp3=ROTL(16, tmp2) = [Y 0 W 0] + // tmp1 + tmp3 = [Y Z W X] + uint tmp1 = packed & 0x00FF00FF; + uint tmp2 = packed & 0xFF00FF00; + uint tmp3 = BitOperations.RotateLeft(tmp2, 16); + + Unsafe.Add(ref dBase, i) = tmp1 + tmp3; + } + } +} diff --git a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs index 30fda7a8e1..3e7e440664 100644 --- a/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs +++ b/src/ImageSharp/Common/Helpers/Shuffle/IShuffle4Slice3.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using static SixLabors.ImageSharp.SimdUtils; @@ -12,26 +13,25 @@ internal interface IShuffle4Slice3 : IComponentShuffle { } -internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3 +internal readonly struct DefaultShuffle4Slice3([ConstantExpected] byte control) : IShuffle4Slice3 { - public DefaultShuffle4Slice3(byte control) - => this.Control = control; - - public byte Control { get; } + public byte Control { get; } = control; [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, this.Control); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) +#pragma warning disable CA1857 // A constant is expected for the parameter + => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, this.Control); +#pragma warning restore CA1857 // A constant is expected for the parameter [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); + ref byte dBase = ref MemoryMarshal.GetReference(destination); SimdUtils.Shuffle.InverseMMShuffle(this.Control, out _, out uint p2, out uint p1, out uint p0); - for (nuint i = 0, j = 0; i < (uint)dest.Length; i += 3, j += 4) + for (nuint i = 0, j = 0; i < (uint)destination.Length; i += 3, j += 4) { Unsafe.Add(ref dBase, i + 0) = Unsafe.Add(ref sBase, p0 + j); Unsafe.Add(ref dBase, i + 1) = Unsafe.Add(ref sBase, p1 + j); @@ -43,14 +43,14 @@ internal readonly struct DefaultShuffle4Slice3 : IShuffle4Slice3 internal readonly struct XYZWShuffle4Slice3 : IShuffle4Slice3 { [MethodImpl(InliningOptions.ShortMethod)] - public void ShuffleReduce(ref ReadOnlySpan source, ref Span dest) - => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref dest, SimdUtils.Shuffle.MMShuffle3210); + public void ShuffleReduce(ref ReadOnlySpan source, ref Span destination) + => HwIntrinsics.Shuffle4Slice3Reduce(ref source, ref destination, SimdUtils.Shuffle.MMShuffle3210); [MethodImpl(InliningOptions.ShortMethod)] - public void Shuffle(ReadOnlySpan source, Span dest) + public void Shuffle(ReadOnlySpan source, Span destination) { ref uint sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); + ref Byte3 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(destination)); nint n = (nint)(uint)source.Length / 4; nint m = Numerics.Modulo4(n); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 4b9a90a952..14d2f1c259 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -63,7 +63,9 @@ internal static partial class SimdUtils ref Span destination, [ConstantExpected] byte control) { - if (Vector512.IsHardwareAccelerated || Vector256.IsHardwareAccelerated || Vector128.IsHardwareAccelerated) + if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat) || + (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat) || + (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat)) { int remainder = 0; if (Vector512.IsHardwareAccelerated) @@ -105,9 +107,11 @@ internal static partial class SimdUtils public static void Shuffle4Reduce( ref ReadOnlySpan source, ref Span destination, - byte control) + [ConstantExpected] byte control) { - if (Vector512.IsHardwareAccelerated || Vector256.IsHardwareAccelerated || Vector128.IsHardwareAccelerated) + if ((Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte) || + (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte) || + (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte)) { int remainder = 0; if (Vector512.IsHardwareAccelerated) @@ -139,7 +143,7 @@ internal static partial class SimdUtils } /// - /// Shuffles 8-bit integer triplets within 128-bit lanes in + /// Shuffles 8-bit integer triplets in /// using the control and store the results in . /// /// The source span of bytes. @@ -149,9 +153,9 @@ internal static partial class SimdUtils public static void Shuffle3Reduce( ref ReadOnlySpan source, ref Span destination, - byte control) + [ConstantExpected] byte control) { - if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsRightShift) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign) { int remainder = source.Length % (Vector128.Count * 3); @@ -171,67 +175,67 @@ internal static partial class SimdUtils } /// - /// Pads then shuffles 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Pads then shuffles 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Pad3Shuffle4Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { int remainder = source.Length % (Vector128.Count * 3); int sourceCount = source.Length - remainder; - int destCount = (int)((uint)sourceCount * 4 / 3); + int destinationCount = (int)((uint)sourceCount * 4 / 3); if (sourceCount > 0) { Pad3Shuffle4( source[..sourceCount], - dest[..destCount], + destination[..destinationCount], control); source = source[sourceCount..]; - dest = dest[destCount..]; + destination = destination[destinationCount..]; } } } /// - /// Shuffles then slices 8-bit integers within 128-bit lanes in - /// using the control and store the results in . + /// Shuffles then slices 8-bit integers in + /// using the control and store the results in . /// /// The source span of bytes. - /// The destination span of bytes. + /// The destination span of bytes. /// The byte control. [MethodImpl(InliningOptions.ShortMethod)] public static void Shuffle4Slice3Reduce( ref ReadOnlySpan source, - ref Span dest, - byte control) + ref Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { int remainder = source.Length & ((Vector128.Count * 4) - 1); // bit-hack for modulo int sourceCount = source.Length - remainder; - int destCount = (int)((uint)sourceCount * 3 / 4); + int destinationCount = (int)((uint)sourceCount * 3 / 4); if (sourceCount > 0) { Shuffle4Slice3( source[..sourceCount], - dest[..destCount], + destination[..destinationCount], control); source = source[sourceCount..]; - dest = dest[destCount..]; + destination = destination[destinationCount..]; } } } @@ -242,12 +246,8 @@ internal static partial class SimdUtils Span destination, [ConstantExpected] byte control) { - if (Vector512.IsHardwareAccelerated) + if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleFloat) { - Span temp = stackalloc int[Vector512.Count]; - Shuffle.MMShuffleSpan(ref temp, control); - Vector512 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); @@ -260,26 +260,22 @@ internal static partial class SimdUtils ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector512.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector512Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector512.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); } } } - else if (Vector256.IsHardwareAccelerated) + else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleFloat) { - Span temp = stackalloc int[Vector256.Count]; - Shuffle.MMShuffleSpan(ref temp, control); - Vector256 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); @@ -292,26 +288,22 @@ internal static partial class SimdUtils ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector256.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector256Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector256.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); } } } - else if (Vector128.IsHardwareAccelerated) + else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleFloat) { - Span temp = stackalloc int[Vector128.Count]; - Shuffle.MMShuffleSpan(ref temp, control); - Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); - ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); @@ -324,17 +316,17 @@ internal static partial class SimdUtils ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector128.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector128Utilities.Shuffle(vs0, control); + Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), control); + Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), control); + Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), control); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector128.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), control); } } } @@ -344,9 +336,9 @@ internal static partial class SimdUtils private static void Shuffle4( ReadOnlySpan source, Span destination, - byte control) + [ConstantExpected] byte control) { - if (Vector512.IsHardwareAccelerated) + if (Vector512.IsHardwareAccelerated && Vector512Utilities.SupportsShuffleByte) { Span temp = stackalloc byte[Vector512.Count]; Shuffle.MMShuffleSpan(ref temp, control); @@ -364,21 +356,21 @@ internal static partial class SimdUtils ref Vector512 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector512 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector512.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector512.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector512Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector512Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector512.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector512Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } - else if (Vector256.IsHardwareAccelerated) + else if (Vector256.IsHardwareAccelerated && Vector256Utilities.SupportsShuffleByte) { Span temp = stackalloc byte[Vector256.Count]; Shuffle.MMShuffleSpan(ref temp, control); @@ -396,21 +388,21 @@ internal static partial class SimdUtils ref Vector256 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector256 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector256.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector256.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector256Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector256Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector256.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector256Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } - else if (Vector128.IsHardwareAccelerated) + else if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte) { Span temp = stackalloc byte[Vector128.Count]; Shuffle.MMShuffleSpan(ref temp, control); @@ -428,17 +420,17 @@ internal static partial class SimdUtils ref Vector128 vs0 = ref Unsafe.Add(ref sourceBase, i); ref Vector128 vd0 = ref Unsafe.Add(ref destinationBase, i); - vd0 = Vector128.Shuffle(vs0, mask); - Unsafe.Add(ref vd0, (nuint)1) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); - Unsafe.Add(ref vd0, (nuint)2) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); - Unsafe.Add(ref vd0, (nuint)3) = Vector128.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); + vd0 = Vector128Utilities.Shuffle(vs0, mask); + Unsafe.Add(ref vd0, (nuint)1) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)1), mask); + Unsafe.Add(ref vd0, (nuint)2) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)2), mask); + Unsafe.Add(ref vd0, (nuint)3) = Vector128Utilities.Shuffle(Unsafe.Add(ref vs0, (nuint)3), mask); } if (m > 0) { for (nuint i = u; i < n; i++) { - Unsafe.Add(ref destinationBase, i) = Vector128.Shuffle(Unsafe.Add(ref sourceBase, i), mask); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.Shuffle(Unsafe.Add(ref sourceBase, i), mask); } } } @@ -448,9 +440,9 @@ internal static partial class SimdUtils private static void Shuffle3( ReadOnlySpan source, Span destination, - byte control) + [ConstantExpected] byte control) { - if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsRightShift) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsRightAlign) { Vector128 maskPad4Nx16 = ShuffleMaskPad4Nx16(); Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); @@ -477,15 +469,15 @@ internal static partial class SimdUtils v2 = Vector128Utilities.AlignRight(v2, v1, 8); v1 = Vector128Utilities.AlignRight(v1, v0, 12); - v0 = Vector128.Shuffle(Vector128.Shuffle(v0, maskPad4Nx16), mask); - v1 = Vector128.Shuffle(Vector128.Shuffle(v1, maskPad4Nx16), mask); - v2 = Vector128.Shuffle(Vector128.Shuffle(v2, maskPad4Nx16), mask); - v3 = Vector128.Shuffle(Vector128.Shuffle(v3, maskPad4Nx16), mask); + v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16), mask); + v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16), mask); + v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16), mask); + v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16), mask); - v0 = Vector128.Shuffle(v0, maskE); - v1 = Vector128.Shuffle(v1, maskSlice4Nx16); - v2 = Vector128.Shuffle(v2, maskE); - v3 = Vector128.Shuffle(v3, maskSlice4Nx16); + v0 = Vector128Utilities.Shuffle(v0, maskE); + v1 = Vector128Utilities.Shuffle(v1, maskSlice4Nx16); + v2 = Vector128Utilities.Shuffle(v2, maskE); + v3 = Vector128Utilities.Shuffle(v3, maskSlice4Nx16); v0 = Vector128Utilities.AlignRight(v1, v0, 4); v3 = Vector128Utilities.AlignRight(v3, v2, 12); @@ -508,21 +500,21 @@ internal static partial class SimdUtils private static void Pad3Shuffle4( ReadOnlySpan source, Span destination, - byte control) + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { - Vector128 vmask = ShuffleMaskPad4Nx16(); - Vector128 vfill = Vector128.Create(0xff000000ff000000ul).AsByte(); + Vector128 maskPad4Nx16 = ShuffleMaskPad4Nx16(); + Vector128 fill = Vector128.Create(0xff000000ff000000ul).AsByte(); - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector128 destBase = + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -532,17 +524,17 @@ internal static partial class SimdUtils ref Vector128 v0 = ref Unsafe.Add(ref sourceBase, i); Vector128 v1 = Unsafe.Add(ref v0, 1); Vector128 v2 = Unsafe.Add(ref v0, 2); - Vector128 v3 = Sse2.ShiftRightLogical128BitLane(v2, 4); + Vector128 v3 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v2 = Ssse3.AlignRight(v2, v1, 8); - v1 = Ssse3.AlignRight(v1, v0, 12); + v2 = Vector128Utilities.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v1, v0, 12); - ref Vector128 vd = ref Unsafe.Add(ref destBase, j); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, j); - vd = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v0, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 1) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v1, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 2) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v2, vmask), vfill), vshuffle); - Unsafe.Add(ref vd, 3) = Ssse3.Shuffle(Sse2.Or(Ssse3.Shuffle(v3, vmask), vfill), vshuffle); + vd = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 1) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 2) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, maskPad4Nx16) | fill, mask); + Unsafe.Add(ref vd, 3) = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, maskPad4Nx16) | fill, mask); } } } @@ -550,23 +542,23 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ShortMethod)] private static void Shuffle4Slice3( ReadOnlySpan source, - Span dest, - byte control) + Span destination, + [ConstantExpected] byte control) { - if (Ssse3.IsSupported) + if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { - Vector128 vmasko = ShuffleMaskSlice4Nx16(); - Vector128 vmaske = Ssse3.AlignRight(vmasko, vmasko, 12); + Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); + Vector128 maskE = Ssse3.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); - Span bytes = stackalloc byte[Vector128.Count]; - Shuffle.MMShuffleSpan(ref bytes, control); - Vector128 vshuffle = Unsafe.As>(ref MemoryMarshal.GetReference(bytes)); + Span temp = stackalloc byte[Vector128.Count]; + Shuffle.MMShuffleSpan(ref temp, control); + Vector128 mask = Unsafe.As>(ref MemoryMarshal.GetReference(temp)); ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 destinationBase = + ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); nuint n = source.Vector128Count(); @@ -579,20 +571,20 @@ internal static partial class SimdUtils Vector128 v2 = Unsafe.Add(ref vs, 2); Vector128 v3 = Unsafe.Add(ref vs, 3); - v0 = Ssse3.Shuffle(Ssse3.Shuffle(v0, vshuffle), vmaske); - v1 = Ssse3.Shuffle(Ssse3.Shuffle(v1, vshuffle), vmasko); - v2 = Ssse3.Shuffle(Ssse3.Shuffle(v2, vshuffle), vmaske); - v3 = Ssse3.Shuffle(Ssse3.Shuffle(v3, vshuffle), vmasko); + v0 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v0, mask), maskE); + v1 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v1, mask), maskSlice4Nx16); + v2 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v2, mask), maskE); + v3 = Vector128Utilities.Shuffle(Vector128Utilities.Shuffle(v3, mask), maskSlice4Nx16); - v0 = Ssse3.AlignRight(v1, v0, 4); - v3 = Ssse3.AlignRight(v3, v2, 12); + v0 = Vector128Utilities.AlignRight(v1, v0, 4); + v3 = Vector128Utilities.AlignRight(v3, v2, 12); - v1 = Sse2.ShiftLeftLogical128BitLane(v1, 4); - v2 = Sse2.ShiftRightLogical128BitLane(v2, 4); + v1 = Vector128Utilities.ShiftLeftBytesInVector(v1, 4); + v2 = Vector128Utilities.ShiftRightBytesInVector(v2, 4); - v1 = Ssse3.AlignRight(v2, v1, 8); + v1 = Vector128Utilities.AlignRight(v2, v1, 8); - ref Vector128 vd = ref Unsafe.Add(ref destBase, j); + ref Vector128 vd = ref Unsafe.Add(ref destinationBase, j); vd = v0; Unsafe.Add(ref vd, 1) = v1; diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index 829362da88..a272e459cb 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -11,20 +11,95 @@ using System.Runtime.Intrinsics.X86; namespace SixLabors.ImageSharp.Common.Helpers; /// -/// Defines utility methods for that have not yet been normalized in the runtime. +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// /// Should only be used if the intrinsics are available. /// internal static class Vector128Utilities { /// - /// Gets a value indicating whether right shift operations are supported. + /// Gets a value indicating whether shuffle operations are supported. /// - public static bool SupportsRightShift + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Sse.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Ssse3.IsSupported || AdvSimd.Arm64.IsSupported; + } + + /// + /// Gets a value indicating whether right align operations are supported. + /// + public static bool SupportsRightAlign { [MethodImpl(MethodImplOptions.AggressiveInlining)] get => Ssse3.IsSupported || AdvSimd.IsSupported; } + /// + /// Gets a value indicating whether right or left byte shift operations are supported. + /// + public static bool SupportsShiftByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Sse2.IsSupported || AdvSimd.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using the control. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + public static Vector128 Shuffle(Vector128 vector, [ConstantExpected] byte control) + { + if (Sse.IsSupported) + { + return Sse.Shuffle(vector, vector, control); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// + /// A new vector containing the values from selected by the given . + /// + public static Vector128 Shuffle(Vector128 vector, Vector128 indices) + { + if (Ssse3.IsSupported) + { + return Ssse3.Shuffle(vector, indices); + } + + if (AdvSimd.Arm64.IsSupported) + { + return AdvSimd.Arm64.VectorTableLookup(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + /// /// Shifts a 128-bit value right by a specified number of bytes while shifting in zeros. /// @@ -80,7 +155,7 @@ internal static class Vector128Utilities /// The . public static Vector128 AlignRight(Vector128 left, Vector128 right, [ConstantExpected(Max = (byte)15)] byte mask) { - if (Sse3.IsSupported) + if (Ssse3.IsSupported) { return Ssse3.AlignRight(left, right, mask); } diff --git a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs new file mode 100644 index 0000000000..14fa24b315 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs @@ -0,0 +1,78 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// +/// Should only be used if the intrinsics are available. +/// +internal static class Vector256Utilities +{ + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx2.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + public static Vector256 Shuffle(Vector256 vector, [ConstantExpected] byte control) + { + if (Avx.IsSupported) + { + return Avx.Shuffle(vector, vector, control); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// The . + public static Vector256 Shuffle(Vector256 vector, Vector256 indices) + { + if (Avx2.IsSupported) + { + return Avx2.Shuffle(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} diff --git a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs new file mode 100644 index 0000000000..5488b40644 --- /dev/null +++ b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs @@ -0,0 +1,80 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.X86; + +namespace SixLabors.ImageSharp.Common.Helpers; + +/// +/// Defines utility methods for that have either: +/// +/// Not yet been normalized in the runtime. +/// Produce codegen that is poorly optimized by the runtime. +/// +/// Should only be used if the intrinsics are available. +/// +internal static class Vector512Utilities +{ + /// + /// Gets a value indicating whether shuffle float operations are supported. + /// + public static bool SupportsShuffleFloat + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx512F.IsSupported; + } + + /// + /// Gets a value indicating whether shuffle byte operations are supported. + /// + public static bool SupportsShuffleByte + { + [MethodImpl(MethodImplOptions.AggressiveInlining)] + get => Avx512BW.IsSupported; + } + + /// + /// Creates a new vector by selecting values from an input vector using the control. + /// + /// The input vector from which values are selected. + /// The shuffle control byte. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Shuffle(Vector512 vector, [ConstantExpected] byte control) + { + if (Avx512F.IsSupported) + { + return Avx512F.Shuffle(vector, vector, control); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Creates a new vector by selecting values from an input vector using a set of indices. + /// + /// The input vector from which values are selected. + /// + /// The per-element indices used to select a value from . + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 Shuffle(Vector512 vector, Vector512 indices) + { + if (Avx512BW.IsSupported) + { + return Avx512BW.Shuffle(vector, indices); + } + + ThrowUnreachableException(); + return default; + } + + [DoesNotReturn] + private static void ThrowUnreachableException() => throw new UnreachableException(); +} From 4c47a7881b75caa57ee8aeaf2eb412d2cdd5a728 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Jan 2024 14:47:04 +1000 Subject: [PATCH 126/219] Fix missed normalization --- src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 14d2f1c259..f27852a823 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -548,7 +548,7 @@ internal static partial class SimdUtils if (Vector128.IsHardwareAccelerated && Vector128Utilities.SupportsShuffleByte && Vector128Utilities.SupportsShiftByte) { Vector128 maskSlice4Nx16 = ShuffleMaskSlice4Nx16(); - Vector128 maskE = Ssse3.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); + Vector128 maskE = Vector128Utilities.AlignRight(maskSlice4Nx16, maskSlice4Nx16, 12); Span temp = stackalloc byte[Vector128.Count]; Shuffle.MMShuffleSpan(ref temp, control); From d9126ea99189408cc80d2e84c8e03ca8917cc2f5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Jan 2024 15:24:01 +1000 Subject: [PATCH 127/219] Attempt to fix left shift --- src/ImageSharp/Common/Helpers/Vector128Utilities.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index a272e459cb..3ca5514948 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -111,7 +111,9 @@ internal static class Vector128Utilities { if (Sse2.IsSupported) { - return Sse2.ShiftRightLogical128BitLane(value, numBytes); +#pragma warning disable CA1857 // A constant is expected for the parameter + return Sse2.ShiftRightLogical128BitLane(value, (byte)(16 - numBytes)); +#pragma warning restore CA1857 // A constant is expected for the parameter } if (AdvSimd.IsSupported) From 5cf8f606e2f94aeb7df1acc91d6ebb0d7c4fdf54 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Jan 2024 16:46:30 +1000 Subject: [PATCH 128/219] Push the right fix! --- src/ImageSharp/Common/Helpers/Vector128Utilities.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index 3ca5514948..1290229d9d 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -111,9 +111,7 @@ internal static class Vector128Utilities { if (Sse2.IsSupported) { -#pragma warning disable CA1857 // A constant is expected for the parameter - return Sse2.ShiftRightLogical128BitLane(value, (byte)(16 - numBytes)); -#pragma warning restore CA1857 // A constant is expected for the parameter + return Sse2.ShiftRightLogical128BitLane(value, numBytes); } if (AdvSimd.IsSupported) @@ -141,7 +139,9 @@ internal static class Vector128Utilities if (AdvSimd.IsSupported) { - return AdvSimd.ExtractVector128(Vector128.Zero, value, numBytes); +#pragma warning disable CA1857 // A constant is expected for the parameter + return AdvSimd.ExtractVector128(Vector128.Zero, value, (byte)(16 - numBytes)); +#pragma warning restore CA1857 // A constant is expected for the parameter } ThrowUnreachableException(); From c9b4edda19f648706b8938b2286bb05383e5fb56 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 15 Jan 2024 17:18:31 +1000 Subject: [PATCH 129/219] Use proper constant --- src/ImageSharp/Common/Helpers/Vector128Utilities.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index 1290229d9d..981f9a47f7 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -140,7 +140,7 @@ internal static class Vector128Utilities if (AdvSimd.IsSupported) { #pragma warning disable CA1857 // A constant is expected for the parameter - return AdvSimd.ExtractVector128(Vector128.Zero, value, (byte)(16 - numBytes)); + return AdvSimd.ExtractVector128(Vector128.Zero, value, (byte)(Vector128.Count - numBytes)); #pragma warning restore CA1857 // A constant is expected for the parameter } From acaebd94d767de3d52a8fbee1d0eedd83a0423b9 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 16 Jan 2024 21:49:33 +1000 Subject: [PATCH 130/219] Update individual pixel implementations --- src/ImageSharp/Color/Color.cs | 6 +- .../Common/Helpers/ColorNumerics.cs | 37 ++- .../PixelFormats/IPackedVector{TPacked}.cs | 2 +- src/ImageSharp/PixelFormats/IPixel.cs | 116 ++++--- .../PixelFormats/PixelImplementations/A8.cs | 98 +++--- .../PixelImplementations/Abgr32.cs | 238 +++++--------- .../PixelImplementations/Argb32.cs | 242 +++++--------- .../PixelImplementations/Bgr24.cs | 199 +++++------- .../PixelImplementations/Bgr565.cs | 116 ++----- .../PixelImplementations/Bgra32.cs | 206 ++++-------- .../PixelImplementations/Bgra4444.cs | 110 ++----- .../PixelImplementations/Bgra5551.cs | 112 ++----- .../PixelImplementations/Byte4.cs | 125 +++----- .../PixelImplementations/HalfSingle.cs | 114 ++----- .../PixelImplementations/HalfVector2.cs | 110 ++----- .../PixelImplementations/HalfVector4.cs | 118 ++----- .../PixelFormats/PixelImplementations/L16.cs | 150 ++++----- .../PixelFormats/PixelImplementations/L8.cs | 144 ++++----- .../PixelFormats/PixelImplementations/La16.cs | 214 +++++-------- .../PixelFormats/PixelImplementations/La32.cs | 237 ++++++-------- .../PixelImplementations/NormalizedByte2.cs | 131 ++------ .../PixelImplementations/NormalizedByte4.cs | 128 ++------ .../PixelImplementations/NormalizedShort2.cs | 126 ++------ .../PixelImplementations/NormalizedShort4.cs | 124 ++----- .../RgbaVector.PixelOperations.cs | 4 +- .../PixelFormats/PixelImplementations/Rg32.cs | 119 ++++--- .../PixelImplementations/Rgb24.cs | 225 +++++-------- .../PixelImplementations/Rgb48.cs | 161 ++++------ .../PixelImplementations/Rgba1010102.cs | 106 ++---- .../PixelImplementations/Rgba32.cs | 269 ++++++---------- .../PixelImplementations/Rgba64.cs | 302 +++++++----------- .../PixelImplementations/RgbaVector.cs | 146 +++------ .../PixelImplementations/Short2.cs | 126 ++------ .../PixelImplementations/Short4.cs | 134 ++------ src/ImageSharp/PixelFormats/README.md | 2 +- .../PixelConversion_ConvertFromRgba32.cs | 26 +- .../ImageSharp.Tests/PixelFormats/L16Tests.cs | 4 +- .../PixelFormats/La32Tests.cs | 4 +- ...ConverterTests.ReferenceImplementations.cs | 2 +- 39 files changed, 1637 insertions(+), 3196 deletions(-) diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index e61abf86fc..3b91a78d15 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -98,10 +98,8 @@ public readonly partial struct Color : IEquatable { return new(pixel.ToScaledVector4()); } - else - { - return new(pixel); - } + + return new(pixel); } /// diff --git a/src/ImageSharp/Common/Helpers/ColorNumerics.cs b/src/ImageSharp/Common/Helpers/ColorNumerics.cs index 553a7c2e89..1c30d857f6 100644 --- a/src/ImageSharp/Common/Helpers/ColorNumerics.cs +++ b/src/ImageSharp/Common/Helpers/ColorNumerics.cs @@ -41,6 +41,34 @@ internal static class ColorNumerics public static byte Get8BitBT709Luminance(byte r, byte g, byte b) => (byte)((r * .2126F) + (g * .7152F) + (b * .0722F) + 0.5F); + /// + /// Gets the luminance from the rgb components using the formula + /// as specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static byte Get8BitBT709Luminance(ushort r, ushort g, ushort b) + => (byte)((From16BitTo8Bit(r) * .2126F) + + (From16BitTo8Bit(g) * .7152F) + + (From16BitTo8Bit(b) * .0722F) + 0.5F); + + /// + /// Gets the luminance from the rgb components using the formula as + /// specified by ITU-R Recommendation BT.709. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort Get16BitBT709Luminance(byte r, byte g, byte b) + => (ushort)((From8BitTo16Bit(r) * .2126F) + + (From8BitTo16Bit(g) * .7152F) + + (From8BitTo16Bit(b) * .0722F) + 0.5F); + /// /// Gets the luminance from the rgb components using the formula as /// specified by ITU-R Recommendation BT.709. @@ -72,8 +100,8 @@ internal static class ColorNumerics /// The 8 bit component value. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static byte DownScaleFrom16BitTo8Bit(ushort component) - { + public static byte From16BitTo8Bit(ushort component) => + // To scale to 8 bits From a 16-bit value V the required value (from the PNG specification) is: // // (V * 255) / 65535 @@ -102,8 +130,7 @@ internal static class ColorNumerics // An alternative arithmetic calculation which also gives no errors is: // // (V * 255 + 32895) >> 16 - return (byte)(((component * 255) + 32895) >> 16); - } + (byte)(((component * 255) + 32895) >> 16); /// /// Scales a value from an 8 bit to @@ -112,7 +139,7 @@ internal static class ColorNumerics /// The 8 bit component value. /// The [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort UpscaleFrom8BitTo16Bit(byte component) + public static ushort From8BitTo16Bit(byte component) => (ushort)(component * 257); /// diff --git a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs index b74c0ff44e..18a8df3481 100644 --- a/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs +++ b/src/ImageSharp/PixelFormats/IPackedVector{TPacked}.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index b28911a904..f9d88deacd 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -14,135 +14,151 @@ namespace SixLabors.ImageSharp.PixelFormats; public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { - /// - /// Gets the pixel type information. - /// - /// The . -#pragma warning disable CA1000 - static abstract PixelTypeInfo GetPixelTypeInfo(); -#pragma warning restore CA1000 - /// /// Creates a instance for this pixel type. /// This method is not intended to be consumed directly. Use instead. /// /// The instance. PixelOperations CreatePixelOperations(); -} -/// -/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. -/// -public interface IPixel -{ - /// - /// Initializes the pixel instance from a generic ("scaled") . - /// - /// The vector to load the pixel from. - void FromScaledVector4(Vector4 vector); +#pragma warning disable CA1000 // Do not declare static members on generic types /// - /// Expands the pixel into a generic ("scaled") representation - /// with values scaled and clamped between 0 and 1. - /// The vector components are typically expanded in least to greatest significance order. + /// Gets the pixel type information. /// - /// The . - Vector4 ToScaledVector4(); + /// The . + static abstract PixelTypeInfo GetPixelTypeInfo(); /// - /// Initializes the pixel instance from a which is specific to the current pixel type. + /// Initializes the pixel instance from a generic scaled . /// - /// The vector to load the pixel from. - void FromVector4(Vector4 vector); + /// The vector to load the pixel from. + /// The . + static abstract TSelf FromScaledVector4(Vector4 source); /// - /// Expands the pixel into a which is specific to the current pixel type. - /// The vector components are typically expanded in least to greatest significance order. + /// Initializes the pixel instance from a which is specific to the current pixel type. /// - /// The . - Vector4 ToVector4(); + /// The vector to load the pixel from. + /// The . + static abstract TSelf FromVector4(Vector4 source); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromArgb32(Argb32 source); + /// The . + static virtual TSelf FromArgb32(Argb32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgra5551(Bgra5551 source); + /// The . + static virtual TSelf FromBgra5551(Bgra5551 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgr24(Bgr24 source); + /// The . + static virtual TSelf FromBgr24(Bgr24 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromBgra32(Bgra32 source); + /// The . + static virtual TSelf FromBgra32(Bgra32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromAbgr32(Abgr32 source); + /// The . + static virtual TSelf FromAbgr32(Abgr32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromL8(L8 source); + /// The . + static virtual TSelf FromL8(L8 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromL16(L16 source); + /// The . + static virtual TSelf FromL16(L16 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromLa16(La16 source); + /// The . + static virtual TSelf FromLa16(La16 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromLa32(La32 source); + /// The . + static virtual TSelf FromLa32(La32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgb24(Rgb24 source); + /// The . + static virtual TSelf FromRgb24(Rgb24 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgba32(Rgba32 source); - - /// - /// Convert the pixel instance into representation. - /// - /// The reference to the destination pixel - void ToRgba32(ref Rgba32 dest); + /// The . + static virtual TSelf FromRgba32(Rgba32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgb48(Rgb48 source); + /// The . + static virtual TSelf FromRgb48(Rgb48 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); /// /// Initializes the pixel instance from an value. /// /// The value. - void FromRgba64(Rgba64 source); + /// The . + static virtual TSelf FromRgba64(Rgba64 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); +#pragma warning restore CA1000 // Do not declare static members on generic types +} + +/// +/// A base interface for all pixels, defining the mandatory operations to be implemented by a pixel type. +/// +public interface IPixel +{ + /// + /// Convert the pixel instance into representation. + /// + /// The + virtual Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToVector4()); + + /// + /// Expands the pixel into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + Vector4 ToScaledVector4(); + + /// + /// Expands the pixel into a which is specific to the current pixel type. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + Vector4 ToVector4(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 23dae82abe..9311c077da 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -41,7 +41,7 @@ public partial struct A8 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(A8 left, A8 right) => left.Equals(right); /// @@ -52,9 +52,21 @@ public partial struct A8 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(A8 left, A8 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new() { A = this.PackedValue }; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -66,80 +78,60 @@ public partial struct A8 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.W); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(0, 0, 0, this.PackedValue / 255F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromVector4(Vector4 source) => new(Pack(source.W)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromArgb32(Argb32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgr24(Bgr24 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgra32(Bgra32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromAbgr32(Abgr32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromL8(L8 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromL16(L16 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromLa16(La16 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.A)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = byte.MaxValue; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = source.A; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgb24(Rgb24 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest = default; - dest.A = this.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgba32(Rgba32 source) => new(source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.PackedValue = byte.MaxValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgb48(Rgb48 source) => new(byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromRgba64(Rgba64 source) => new(ColorNumerics.From16BitTo8Bit(source.A)); /// /// Compares an object with the packed vector. @@ -153,7 +145,6 @@ public partial struct A8 : IPixel, IPackedVector /// /// The A8 packed vector to compare. /// True if the packed vectors are equal. - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(A8 other) => this.PackedValue.Equals(other.PackedValue); /// @@ -163,7 +154,6 @@ public partial struct A8 : IPixel, IPackedVector public override readonly string ToString() => $"A8({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -171,6 +161,6 @@ public partial struct A8 : IPixel, IPackedVector /// /// The float containing the value to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1F) * 255F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(float alpha) => (byte)Math.Round(Numerics.Clamp(alpha, 0, 1f) * 255f); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 742f27cc02..2a29292a0c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -44,12 +45,12 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// The maximum byte value. /// - private static readonly Vector4 MaxBytes = new(255); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); /// /// The half vector value. /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -57,7 +58,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +74,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,9 +90,9 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this() => Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -99,9 +100,9 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector3 vector) - : this() => this.Pack(ref vector); + : this() => Pack(vector); /// /// Initializes a new instance of the struct. @@ -109,9 +110,9 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector4 vector) - : this() => this.Pack(ref vector); + : this() => Pack(vector); /// /// Initializes a new instance of the struct. @@ -119,29 +120,29 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(uint packed) : this() => this.Abgr = packed; /// - /// Gets or sets the packed representation of the Abgrb32 struct. + /// Gets or sets the packed representation of the Abgr struct. /// public uint Abgr { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Abgr; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Abgr = value; } @@ -153,7 +154,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Abgr32 left, Abgr32 right) => left.Equals(right); /// @@ -164,9 +165,21 @@ public partial struct Abgr32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Abgr32 left, Abgr32 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -178,157 +191,87 @@ public partial struct Abgr32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromAbgr32(Abgr32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - // We can assign the Bgr24 value directly to last three bytes of this instance. - ref byte thisRef = ref Unsafe.As(ref this); - ref byte thisRefFromB = ref Unsafe.AddByteOffset(ref thisRef, 1); - Unsafe.As(ref thisRefFromB) = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromL16(L16 source) { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromLa32(La32 source) { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Abgr32 abgr32 && this.Equals(abgr32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Abgr32 other) => this.Abgr == other.Abgr; /// @@ -338,7 +281,6 @@ public partial struct Abgr32 : IPixel, IPackedVector public override readonly string ToString() => $"Abgr({this.A}, {this.B}, {this.G}, {this.R})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Abgr.GetHashCode(); /// @@ -348,38 +290,28 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The y-component /// The z-component /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); /// /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1)); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Abgr32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 7a8ee2a63a..51ef76ad6b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -41,15 +42,8 @@ public partial struct Argb32 : IPixel, IPackedVector /// public byte B; - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -57,7 +51,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(byte r, byte g, byte b) { this.R = r; @@ -73,7 +67,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(byte r, byte g, byte b, byte a) { this.R = r; @@ -89,9 +83,9 @@ public partial struct Argb32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this() => Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -99,9 +93,9 @@ public partial struct Argb32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector3 vector) - : this() => this.Pack(ref vector); + : this() => Pack(vector); /// /// Initializes a new instance of the struct. @@ -109,9 +103,9 @@ public partial struct Argb32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector4 vector) - : this() => this.Pack(ref vector); + : this() => Pack(vector); /// /// Initializes a new instance of the struct. @@ -119,7 +113,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(uint packed) : this() => this.Argb = packed; @@ -128,20 +122,20 @@ public partial struct Argb32 : IPixel, IPackedVector /// public uint Argb { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Argb; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Argb = value; } @@ -153,7 +147,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Argb32 left, Argb32 right) => left.Equals(right); /// @@ -164,9 +158,21 @@ public partial struct Argb32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Argb32 left, Argb32 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -178,156 +184,87 @@ public partial struct Argb32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromArgb32(Argb32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = source.PackedValue; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Argb32 argb32 && this.Equals(argb32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Argb32 other) => this.Argb == other.Argb; /// @@ -337,7 +274,6 @@ public partial struct Argb32 : IPixel, IPackedVector public override readonly string ToString() => $"Argb({this.A}, {this.R}, {this.G}, {this.B})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Argb.GetHashCode(); /// @@ -347,38 +283,28 @@ public partial struct Argb32 : IPixel, IPackedVector /// The y-component /// The z-component /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Argb32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); /// /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Argb32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1f)); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Argb32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index bdf7d1a7e2..4756f5e199 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,40 +15,36 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// +/// +/// Initializes a new instance of the struct. +/// +/// The red component. +/// The green component. +/// The blue component. [StructLayout(LayoutKind.Explicit)] -public partial struct Bgr24 : IPixel +[method: MethodImpl(MethodImplOptions.AggressiveInlining)] +public partial struct Bgr24(byte r, byte g, byte b) : IPixel { /// /// The blue component. /// [FieldOffset(0)] - public byte B; + public byte B = b; /// /// The green component. /// [FieldOffset(1)] - public byte G; + public byte G = g; /// /// The red component. /// [FieldOffset(2)] - public byte R; + public byte R = r; - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] - public Bgr24(byte r, byte g, byte b) - { - this.R = r; - this.G = g; - this.B = b; - } + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Compares two objects for equality. @@ -57,7 +54,7 @@ public partial struct Bgr24 : IPixel /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgr24 left, Bgr24 right) => left.Equals(right); /// @@ -68,9 +65,21 @@ public partial struct Bgr24 : IPixel /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgr24 left, Bgr24 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, byte.MaxValue) / MaxBytes; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -82,143 +91,90 @@ public partial struct Bgr24 : IPixel public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromVector4(Vector4 source) { - Rgba32 rgba = default; - rgba.FromVector4(vector); - this.FromRgba32(rgba); - } + source *= MaxBytes; + source += Half; + source = Numerics.Clamp(source, Vector4.Zero, MaxBytes); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; + Vector128 result = Vector128.ConvertToInt32(source.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromLa16(La16 source) => new(source.L, source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - // We can assign this instances value directly to last three bytes of the Abgr32. - ref byte sourceRef = ref Unsafe.As(ref source); - ref byte sourceRefFromB = ref Unsafe.AddByteOffset(ref sourceRef, 1); - this = Unsafe.As(ref sourceRefFromB); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source.Bgr; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgr24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// @@ -228,6 +184,5 @@ public partial struct Bgr24 : IPixel public override readonly string ToString() => $"Bgr24({this.B}, {this.G}, {this.R})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.B, this.G); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 0874eb8251..4ea149dda9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -13,7 +13,13 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct Bgr565 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// +/// The vector containing the components for the packed value. +/// +public partial struct Bgr565(Vector3 vector) : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -26,16 +32,8 @@ public partial struct Bgr565 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed value. - /// - public Bgr565(Vector3 vector) => this.PackedValue = Pack(ref vector); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -45,7 +43,7 @@ public partial struct Bgr565 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgr565 left, Bgr565 right) => left.Equals(right); /// @@ -56,9 +54,17 @@ public partial struct Bgr565 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgr565 left, Bgr565 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -70,87 +76,19 @@ public partial struct Bgr565 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector3 = new Vector3(vector.X, vector.Y, vector.Z); - this.PackedValue = Pack(ref vector3); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector3(), 1F); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromVector4(source.ToVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromVector4(source.ToVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromVector4(source.ToVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromVector4(source.ToVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromVector4(source.ToVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector3(source.X, source.Y, source.Z)) }; /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector3 ToVector3() => new( ((this.PackedValue >> 11) & 0x1F) * (1F / 31F), ((this.PackedValue >> 5) & 0x3F) * (1F / 63F), @@ -160,22 +98,20 @@ public partial struct Bgr565 : IPixel, IPackedVector public override readonly bool Equals(object? obj) => obj is Bgr565 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgr565 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector3(); + Vector3 vector = this.ToVector3(); return FormattableString.Invariant($"Bgr565({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector3 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector3 vector) { vector = Vector3.Clamp(vector, Vector3.Zero, Vector3.One); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index f508463574..aeffd57602 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -38,15 +39,8 @@ public partial struct Bgra32 : IPixel, IPackedVector /// public byte A; - /// - /// The maximum byte value. - /// - private static readonly Vector4 MaxBytes = new(255); - - /// - /// The half vector value. - /// - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -54,7 +48,7 @@ public partial struct Bgra32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32(byte r, byte g, byte b) { this.R = r; @@ -70,7 +64,7 @@ public partial struct Bgra32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Bgra32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,10 +78,10 @@ public partial struct Bgra32 : IPixel, IPackedVector /// public uint Bgra { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -106,7 +100,7 @@ public partial struct Bgra32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra32 left, Bgra32 right) => left.Equals(right); /// @@ -117,9 +111,21 @@ public partial struct Bgra32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra32 left, Bgra32 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -131,150 +137,82 @@ public partial struct Bgra32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgra32(Bgra32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = byte.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// public override readonly bool Equals(object? obj) => obj is Bgra32 other && this.Equals(other); @@ -292,16 +230,14 @@ public partial struct Bgra32 : IPixel, IPackedVector /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Bgra32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 4bb3f8a0e8..baaa49ce11 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -public partial struct Bgra4444 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the components for the packed vector. +public partial struct Bgra4444(Vector4 vector) : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -26,14 +30,8 @@ public partial struct Bgra4444 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the components for the packed vector. - public Bgra4444(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -43,7 +41,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra4444 left, Bgra4444 right) => left.Equals(right); /// @@ -54,120 +52,62 @@ public partial struct Bgra4444 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 4, 4, 4, 4), - PixelColorType.BGR | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() { - const float Max = 1 / 15F; + const float max = 1 / 15f; return new Vector4( (this.PackedValue >> 8) & 0x0F, (this.PackedValue >> 4) & 0x0F, this.PackedValue & 0x0F, - (this.PackedValue >> 12) & 0x0F) * Max; + (this.PackedValue >> 12) & 0x0F) * max; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 4, 4, 4, 4), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is Bgra4444 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgra4444 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Bgra4444({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)((((int)Math.Round(vector.W * 15F) & 0x0F) << 12) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index d57545deea..381f4628f0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -13,7 +13,13 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -public partial struct Bgra5551 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// +/// The vector containing the components for the packed vector. +/// +public partial struct Bgra5551(Vector4 vector) : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -27,16 +33,8 @@ public partial struct Bgra5551 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// - /// The vector containing the components for the packed vector. - /// - public Bgra5551(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -46,7 +44,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Bgra5551 left, Bgra5551 right) => left.Equals(right); /// @@ -57,33 +55,15 @@ public partial struct Bgra5551 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 5, 5, 5, 1), - PixelColorType.BGR | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( ((this.PackedValue >> 10) & 0x1F) / 31F, ((this.PackedValue >> 5) & 0x1F) / 31F, @@ -91,81 +71,45 @@ public partial struct Bgra5551 : IPixel, IPackedVector (this.PackedValue >> 15) & 0x01); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this = source; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 5, 5, 5, 1), + PixelColorType.BGR | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgra5551(Bgra5551 source) => new() { PackedValue = source.PackedValue }; /// - public override bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other); + public override readonly bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Bgra5551 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Bgra5551({vector.Z:#0.##}, {vector.Y:#0.##}, {vector.X:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static ushort Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); return (ushort)( diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index d8f1dd0acb..fba3206728 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,13 +15,18 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct Byte4 : IPixel, IPackedVector { + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + /// /// Initializes a new instance of the struct. /// /// /// A vector containing the initial values for the components of the Byte4 structure. /// - public Byte4(Vector4 vector) => this.PackedValue = Pack(ref vector); + public Byte4(Vector4 vector) => this.PackedValue = Pack(vector); /// /// Initializes a new instance of the struct. @@ -31,8 +37,8 @@ public partial struct Byte4 : IPixel, IPackedVector /// The w-component public Byte4(float x, float y, float z, float w) { - var vector = new Vector4(x, y, z, w); - this.PackedValue = Pack(ref vector); + Vector4 vector = new(x, y, z, w); + this.PackedValue = Pack(vector); } /// @@ -46,7 +52,7 @@ public partial struct Byte4 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Byte4 left, Byte4 right) => left.Equals(right); /// @@ -57,110 +63,60 @@ public partial struct Byte4 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Byte4 left, Byte4 right) => !left.Equals(right); /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 8, 8, 8, 8), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector * 255F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgba32 ToRgba32() => new() { PackedValue = this.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255F; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4() / 255f; /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( this.PackedValue & 0xFF, - (this.PackedValue >> 0x8) & 0xFF, - (this.PackedValue >> 0x10) & 0xFF, - (this.PackedValue >> 0x18) & 0xFF); + (this.PackedValue >> 8) & 0xFF, + (this.PackedValue >> 16) & 0xFF, + (this.PackedValue >> 24) & 0xFF); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromScaledVector4(Vector4 source) => FromVector4(source * 255f); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue }; /// public override readonly bool Equals(object? obj) => obj is Byte4 byte4 && this.Equals(byte4); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Byte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Byte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } @@ -169,18 +125,17 @@ public partial struct Byte4 : IPixel, IPackedVector /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { - const float Max = 255F; + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - // Clamp the value between min and max values - vector = Numerics.Clamp(vector, Vector4.Zero, new Vector4(Max)); + Vector128 result = Vector128.ConvertToUInt32(vector.AsVector128()); - uint byte4 = (uint)Math.Round(vector.X) & 0xFF; - uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; - uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; - uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; + uint byte4 = result.GetElement(0) & 0xFF; + uint byte3 = result.GetElement(1) << 8; + uint byte2 = result.GetElement(2) << 16; + uint byte1 = result.GetElement(3) << 24; return byte4 | byte3 | byte2 | byte1; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 01ae9fc5f5..2d8ab5ff08 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -12,16 +12,14 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, 0, 0, 1] to [1, 0, 0, 1] in vector form. /// /// -public partial struct HalfSingle : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The single component value. +public partial struct HalfSingle(float value) : IPixel, IPackedVector { - /// - /// Initializes a new instance of the struct. - /// - /// The single component value. - public HalfSingle(float value) => this.PackedValue = HalfTypeHelper.Pack(value); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = HalfTypeHelper.Pack(value); /// /// Compares two objects for equality. @@ -31,7 +29,7 @@ public partial struct HalfSingle : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfSingle left, HalfSingle right) => left.Equals(right); /// @@ -42,31 +40,11 @@ public partial struct HalfSingle : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(1, 16), - PixelColorType.Red, - PixelAlphaRepresentation.None); - - /// - public PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - float scaled = vector.X; - scaled *= 2F; - scaled--; - this.PackedValue = HalfTypeHelper.Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { float single = this.ToSingle() + 1F; @@ -75,87 +53,49 @@ public partial struct HalfSingle : IPixel, IPackedVector } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = HalfTypeHelper.Pack(vector.X); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new(this.ToSingle(), 0, 0, 1F); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(1, 16), + PixelColorType.Red, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromScaledVector4(Vector4 source) + { + float scaled = source.X; + scaled *= 2F; + scaled--; + return new() { PackedValue = HalfTypeHelper.Pack(scaled) }; + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromVector4(Vector4 source) => new() { PackedValue = HalfTypeHelper.Pack(source.X) }; /// /// Expands the packed representation into a . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly float ToSingle() => HalfTypeHelper.Unpack(this.PackedValue); /// public override readonly bool Equals(object? obj) => obj is HalfSingle other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfSingle other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => FormattableString.Invariant($"HalfSingle({this.ToSingle():#0.##})"); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index d591dd8550..525638b1da 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -38,7 +38,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfVector2 left, HalfVector2 right) => left.Equals(right); /// @@ -49,111 +49,55 @@ public partial struct HalfVector2 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(2, 16, 16), - PixelColorType.Red | PixelColorType.Green, - PixelAlphaRepresentation.None); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; - scaled -= Vector2.One; - this.PackedValue = Pack(scaled.X, scaled.Y); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector2(); + Vector2 scaled = this.ToVector2(); scaled += Vector2.One; scaled /= 2F; - return new Vector4(scaled, 0F, 1F); + return new(scaled, 0F, 1F); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(vector.X, vector.Y); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() { - var vector = this.ToVector2(); - return new Vector4(vector.X, vector.Y, 0F, 1F); + Vector2 vector = this.ToVector2(); + return new(vector.X, vector.Y, 0F, 1F); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(2, 16, 16), + PixelColorType.Red | PixelColorType.Green, + PixelAlphaRepresentation.None); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromScaledVector4(Vector4 source) + { + Vector2 scaled = new Vector2(source.X, source.Y) * 2F; + scaled -= Vector2.One; + return new() { PackedValue = Pack(scaled.X, scaled.Y) }; + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromVector4(Vector4 source) => new() { PackedValue = Pack(source.X, source.Y) }; /// /// Expands the packed representation into a . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() { Vector2 vector; @@ -166,21 +110,19 @@ public partial struct HalfVector2 : IPixel, IPackedVector public override readonly bool Equals(object? obj) => obj is HalfVector2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfVector2 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"HalfVector2({vector.X:#0.##}, {vector.Y:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(float x, float y) { uint num2 = HalfTypeHelper.Pack(x); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index ca6bff2305..28f3849ebe 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct HalfVector4 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// A vector containing the initial values for the components +public partial struct HalfVector4(Vector4 vector) : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -26,14 +30,8 @@ public partial struct HalfVector4 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components - public HalfVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public ulong PackedValue { get; set; } + public ulong PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -43,7 +41,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(HalfVector4 left, HalfVector4 right) => left.Equals(right); /// @@ -54,44 +52,21 @@ public partial struct HalfVector4 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 16, 16, 16, 16), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; scaled /= 2F; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( HalfTypeHelper.Unpack((ushort)this.PackedValue), HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x10)), @@ -99,77 +74,42 @@ public partial struct HalfVector4 : IPixel, IPackedVector HalfTypeHelper.Unpack((ushort)(this.PackedValue >> 0x30))); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromScaledVector4(Vector4 source) + { + source *= 2F; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is HalfVector4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(HalfVector4 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"HalfVector4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// @@ -177,8 +117,8 @@ public partial struct HalfVector4 : IPixel, IPackedVector /// /// The vector containing the values to pack. /// The containing the packed values. - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { ulong num4 = HalfTypeHelper.Pack(vector.X); ulong num3 = (ulong)HalfTypeHelper.Pack(vector.Y) << 0x10; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 8522da3fbc..52bb85fe27 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -12,18 +12,16 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct L16 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The luminance component +public partial struct L16(ushort luminance) : IPixel, IPackedVector { private const float Max = ushort.MaxValue; - /// - /// Initializes a new instance of the struct. - /// - /// The luminance component - public L16(ushort luminance) => this.PackedValue = luminance; - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = luminance; /// /// Compares two objects for equality. @@ -33,7 +31,7 @@ public partial struct L16 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(L16 left, L16 right) => left.Equals(right); /// @@ -44,9 +42,29 @@ public partial struct L16 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(L16 left, L16 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = ColorNumerics.From16BitTo8Bit(this.PackedValue); + return new(rgb, rgb, rgb); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + float scaled = this.PackedValue / Max; + return new Vector4(scaled, scaled, scaled, 1f); + } + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -58,127 +76,77 @@ public partial struct L16 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - float scaled = this.PackedValue / Max; - return new Vector4(scaled, scaled, scaled, 1F); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromArgb32(Argb32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromL16(L16 source) => new(source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromLa16(La16 source) => new(ColorNumerics.From8BitTo16Bit(source.L)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = source.L; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromLa32(La32 source) => new(source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.PackedValue); - dest.R = rgb; - dest.G = rgb; - dest.B = rgb; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.PackedValue = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// public override readonly bool Equals(object? obj) => obj is L16 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(L16 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"L16({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ushort Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.PackedValue = ColorNumerics.Get16BitBT709Luminance( - vector.X, - vector.Y, - vector.Z); + return ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 706fc11014..7c47ab10cc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -12,19 +13,24 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct L8 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The luminance component. +public partial struct L8(byte luminance) : IPixel, IPackedVector { - private static readonly Vector4 MaxBytes = new(255F); - private static readonly Vector4 Half = new(0.5F); + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); /// - /// Initializes a new instance of the struct. + /// The half vector value. /// - /// The luminance component. - public L8(byte luminance) => this.PackedValue = luminance; + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// - public byte PackedValue { get; set; } + public byte PackedValue { get; set; } = luminance; /// /// Compares two objects for equality. @@ -34,7 +40,7 @@ public partial struct L8 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(L8 left, L8 right) => left.Equals(right); /// @@ -45,9 +51,29 @@ public partial struct L8 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(L8 left, L8 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = this.PackedValue; + return new(rgb, rgb, rgb); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + float rgb = this.PackedValue / 255f; + return new Vector4(rgb, rgb, rgb, 1f); + } + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -59,115 +85,81 @@ public partial struct L8 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - float rgb = this.PackedValue / 255F; - return new Vector4(rgb, rgb, rgb, 1F); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromL8(L8 source) => new(source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromLa16(La16 source) => new(source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.PackedValue = source.L; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.PackedValue = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.PackedValue = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.PackedValue; - dest.G = this.PackedValue; - dest.B = this.PackedValue; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - => this.PackedValue = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - => this.PackedValue = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// public override readonly bool Equals(object? obj) => obj is L8 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(L8 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"L8({this.PackedValue})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.PackedValue = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index e306731534..558f15332a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -13,34 +14,35 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// +/// +/// Initializes a new instance of the struct. +/// +/// The luminance component. +/// The alpha component. [StructLayout(LayoutKind.Explicit)] -public partial struct La16 : IPixel, IPackedVector +public partial struct La16(byte l, byte a) : IPixel, IPackedVector { - private static readonly Vector4 MaxBytes = new(255F); - private static readonly Vector4 Half = new(0.5F); + /// + /// The maximum byte value. + /// + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + + /// + /// The half vector value. + /// + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Gets or sets the luminance component. /// [FieldOffset(0)] - public byte L; + public byte L = l; /// /// Gets or sets the alpha component. /// [FieldOffset(1)] - public byte A; - - /// - /// Initializes a new instance of the struct. - /// - /// The luminance component. - /// The alpha component. - public La16(byte l, byte a) - { - this.L = l; - this.A = a; - } + public byte A = a; /// public ushort PackedValue @@ -57,7 +59,7 @@ public partial struct La16 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(La16 left, La16 right) => left.Equals(right); /// @@ -68,9 +70,26 @@ public partial struct La16 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(La16 left, La16 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.L, this.L, this.L, this.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + const float max = 255f; + float rgb = this.L / max; + return new Vector4(rgb, rgb, rgb, this.A / max); + } + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -82,160 +101,83 @@ public partial struct La16 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue); - - /// - public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other); - - /// - public override readonly string ToString() => $"La16({this.L}, {this.A})"; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromScaledVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromL16(L16 source) => new(ColorNumerics.From16BitTo8Bit(source.PackedValue), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.L = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromL8(L8 source) => new(source.PackedValue, byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromLa16(La16 source) => new(source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - this.L = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromLa32(La32 source) => new(ColorNumerics.From16BitTo8Bit(source.L), ColorNumerics.From16BitTo8Bit(source.A)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgb24(Rgb24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); - - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgba32(Rgba32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromRgb48(Rgb48 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// - public void FromRgba64(Rgba64 source) - { - this.L = ColorNumerics.Get8BitBT709Luminance( - ColorNumerics.DownScaleFrom16BitTo8Bit(source.R), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.G), - ColorNumerics.DownScaleFrom16BitTo8Bit(source.B)); - - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + public static La16 FromRgba64(Rgba64 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), ColorNumerics.From16BitTo8Bit(source.A)); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + /// + public override readonly bool Equals(object? obj) => obj is La16 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + public readonly bool Equals(La16 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.L; - dest.G = this.L; - dest.B = this.L; - dest.A = this.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + public override readonly string ToString() => $"La16({this.L}, {this.A})"; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - const float Max = 255F; - float rgb = this.L / Max; - return new Vector4(rgb, rgb, rgb, this.A / Max); - } + /// + public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static La16 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.L = ColorNumerics.Get8BitBT709Luminance((byte)vector.X, (byte)vector.Y, (byte)vector.Z); - this.A = (byte)vector.W; + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + byte l = ColorNumerics.Get8BitBT709Luminance(result.GetElement(0), result.GetElement(4), result.GetElement(8)); + byte a = result.GetElement(12); + + return new(l, a); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 867bfacd36..c0d0243563 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -13,8 +13,13 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// +/// +/// Initializes a new instance of the struct. +/// +/// The luminance component. +/// The alpha component. [StructLayout(LayoutKind.Explicit)] -public partial struct La32 : IPixel, IPackedVector +public partial struct La32(ushort l, ushort a) : IPixel, IPackedVector { private const float Max = ushort.MaxValue; @@ -22,32 +27,21 @@ public partial struct La32 : IPixel, IPackedVector /// Gets or sets the luminance component. /// [FieldOffset(0)] - public ushort L; + public ushort L = l; /// /// Gets or sets the alpha component. /// [FieldOffset(2)] - public ushort A; - - /// - /// Initializes a new instance of the struct. - /// - /// The luminance component. - /// The alpha component. - public La32(ushort l, ushort a) - { - this.L = l; - this.A = a; - } + public ushort A = a; /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -59,7 +53,7 @@ public partial struct La32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(La32 left, La32 right) => left.Equals(right); /// @@ -70,9 +64,29 @@ public partial struct La32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(La32 left, La32 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + { + byte rgb = ColorNumerics.From16BitTo8Bit(this.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(this.A)); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() + { + float rgb = this.L / Max; + return new Vector4(rgb, rgb, rgb, this.A / Max); + } + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -84,179 +98,108 @@ public partial struct La32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue); - - /// - public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other); - - /// - public override readonly string ToString() => $"La32({this.L}, {this.A})"; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromScaledVector4(Vector4 source) => Pack(source); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromArgb32(Argb32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgra32(Bgra32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromAbgr32(Abgr32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.L = source.PackedValue; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromL16(L16 source) => new(source.PackedValue, ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue), ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromLa16(La16 source) { - this.L = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.From8BitTo16Bit(source.L); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this = source; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromLa32(La32 source) => new(source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgb24(Rgb24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgb48(Rgb48 source) { - this.L = ColorNumerics.Get16BitBT709Luminance( - ColorNumerics.UpscaleFrom8BitTo16Bit(source.R), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.G), - ColorNumerics.UpscaleFrom8BitTo16Bit(source.B)); - - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + return new(l, ushort.MaxValue); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgba32(Rgba32 source) { - this.L = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); - this.A = source.A; + ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); + ushort a = ColorNumerics.From8BitTo16Bit(source.A); + return new(l, a); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromRgba64(Rgba64 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), source.A); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.ConvertFromRgbaScaledVector4(vector); + /// + public override readonly bool Equals(object? obj) => obj is La32 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(this.L); - dest.R = rgb; - dest.G = rgb; - dest.B = rgb; - dest.A = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - } + public readonly bool Equals(La32 other) => this.PackedValue.Equals(other.PackedValue); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + /// + public override readonly string ToString() => $"La32({this.L}, {this.A})"; - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() - { - float scaled = this.L / Max; - return new Vector4(scaled, scaled, scaled, this.A / Max); - } + /// + public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - internal void ConvertFromRgbaScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static La32 Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.L = ColorNumerics.Get16BitBT709Luminance( - vector.X, - vector.Y, - vector.Z); - - this.A = (ushort)MathF.Round(vector.W); + ushort l = ColorNumerics.Get16BitBT709Luminance(vector.X, vector.Y, vector.Z); + ushort a = (ushort)MathF.Round(vector.W); + return new(l, a); } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index c5eb2c2ded..138490b9cc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -12,12 +12,15 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -public partial struct NormalizedByte2 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct NormalizedByte2(Vector2 vector) : IPixel, IPackedVector { - private const float MaxPos = 127F; - + private const float MaxPos = 127f; private static readonly Vector2 Half = new(MaxPos); - private static readonly Vector2 MinusOne = new(-1F); + private static readonly Vector2 MinusOne = new(-1f); /// /// Initializes a new instance of the struct. @@ -29,14 +32,8 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); - /// - public ushort PackedValue { get; set; } + public ushort PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -46,7 +43,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedByte2 left, NormalizedByte2 right) => left.Equals(right); /// @@ -57,9 +54,23 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() + { + Vector2 scaled = this.ToVector2(); + scaled += Vector2.One; + scaled /= 2f; + return new Vector4(scaled, 0f, 1f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -71,98 +82,24 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromScaledVector4(Vector4 source) { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; + Vector2 scaled = new Vector2(source.X, source.Y) * 2f; scaled -= Vector2.One; - this.PackedValue = Pack(scaled); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); + return new() { PackedValue = Pack(scaled) }; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new( (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos, (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos); @@ -171,21 +108,19 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector obj is NormalizedByte2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedByte2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"NormalizedByte2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static ushort Pack(Vector2 vector) { vector = Vector2.Clamp(vector, MinusOne, Vector2.One) * Half; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 6cf92688ed..d9a3cc1cd9 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -12,12 +13,15 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct NormalizedByte4 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct NormalizedByte4(Vector4 vector) : IPixel, IPackedVector { - private const float MaxPos = 127F; - - private static readonly Vector4 Half = new(MaxPos); - private static readonly Vector4 MinusOne = new(-1F); + private const float MaxPos = 127f; + private static readonly Vector4 Half = Vector128.Create(MaxPos).AsVector4(); + private static readonly Vector4 MinusOne = Vector128.Create(-1f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -31,14 +35,8 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public uint PackedValue { get; set; } + public uint PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -48,7 +46,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedByte4 left, NormalizedByte4 right) => left.Equals(right); /// @@ -59,44 +57,21 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 8, 8, 8, 8), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( (sbyte)((this.PackedValue >> 0) & 0xFF) / MaxPos, (sbyte)((this.PackedValue >> 8) & 0xFF) / MaxPos, @@ -104,81 +79,46 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector> 24) & 0xFF) / MaxPos); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 8, 8, 8, 8), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromScaledVector4(Vector4 source) + { + source *= 2f; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is NormalizedByte4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedByte4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"NormalizedByte4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { vector = Numerics.Clamp(vector, MinusOne, Vector4.One) * Half; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 03fa2737ee..8971e9879e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -public partial struct NormalizedShort2 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct NormalizedShort2(Vector2 vector) : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -30,14 +34,8 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); - /// - public uint PackedValue { get; set; } + public uint PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -47,7 +45,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedShort2 left, NormalizedShort2 right) => left.Equals(right); /// @@ -58,9 +56,23 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedShort2 left, NormalizedShort2 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() + { + Vector2 scaled = this.ToVector2(); + scaled += Vector2.One; + scaled /= 2f; + return new Vector4(scaled, 0f, 1f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -72,98 +84,24 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromScaledVector4(Vector4 source) { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 2F; + Vector2 scaled = new Vector2(source.X, source.Y) * 2f; scaled -= Vector2.One; - this.PackedValue = Pack(scaled); + return new() { PackedValue = Pack(scaled) }; } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += Vector2.One; - scaled /= 2F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.ToVector2(), 0, 1); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new( (short)(this.PackedValue & 0xFFFF) / MaxPos, (short)(this.PackedValue >> 0x10) / MaxPos); @@ -172,21 +110,19 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector public override readonly bool Equals(object? obj) => obj is NormalizedShort2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedShort2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"NormalizedShort2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector *= Max; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 89ba2a23ba..7271980763 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -12,12 +13,15 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -public partial struct NormalizedShort4 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct NormalizedShort4(Vector4 vector) : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; - - private static readonly Vector4 Max = new(MaxPos); + private static readonly Vector4 Max = Vector128.Create(MaxPos).AsVector4(); private static readonly Vector4 Min = Vector4.Negate(Max); /// @@ -32,14 +36,8 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public ulong PackedValue { get; set; } + public ulong PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -49,7 +47,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(NormalizedShort4 left, NormalizedShort4 right) => left.Equals(right); /// @@ -60,44 +58,21 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedShort4 left, NormalizedShort4 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 16, 16, 16, 16), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 2F; - vector -= Vector4.One; - this.FromVector4(vector); - } - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); + Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new( (short)((this.PackedValue >> 0x00) & 0xFFFF) / MaxPos, (short)((this.PackedValue >> 0x10) & 0xFFFF) / MaxPos, @@ -105,81 +80,46 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector (short)((this.PackedValue >> 0x30) & 0xFFFF) / MaxPos); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromScaledVector4(Vector4 source) + { + source *= 2f; + source -= Vector4.One; + return FromVector4(source); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is NormalizedShort4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(NormalizedShort4 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"NormalizedShort4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { vector *= Max; vector = Numerics.Clamp(vector, Min, Max); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs index c18c3d8687..128fd8dafd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs @@ -71,7 +71,7 @@ public partial struct RgbaVector ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref L8 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.ConvertFromRgbaScaledVector4(sp); + dp.Pack(sp); } } @@ -90,7 +90,7 @@ public partial struct RgbaVector ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); ref L16 dp = ref Unsafe.Add(ref destBaseRef, i); - dp.ConvertFromRgbaScaledVector4(sp); + dp.Pack(sp); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 8f2e198405..c31bfc6132 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -public partial struct Rg32 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct Rg32(Vector2 vector) : IPixel, IPackedVector { private static readonly Vector2 Max = new(ushort.MaxValue); @@ -26,14 +30,8 @@ public partial struct Rg32 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); - /// - public uint PackedValue { get; set; } + public uint PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -43,7 +41,7 @@ public partial struct Rg32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rg32 left, Rg32 right) => left.Equals(right); /// @@ -54,9 +52,26 @@ public partial struct Rg32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rg32 left, Rg32 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + => new( + ColorNumerics.From16BitTo8Bit((ushort)(this.PackedValue & 0xFFFF)), + ColorNumerics.From16BitTo8Bit((ushort)(this.PackedValue >> 16)), + byte.MinValue, + byte.MaxValue); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.ToVector2(), 0f, 1f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -68,108 +83,86 @@ public partial struct Rg32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.ToVector2(), 0F, 1F); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromArgb32(Argb32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromBgr24(Bgr24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromAbgr32(Abgr32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromL8(L8 source) => new(ColorNumerics.From8BitTo16Bit(source.PackedValue), ColorNumerics.From8BitTo16Bit(source.PackedValue)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromL16(L16 source) => new(source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromLa16(La16 source) => new(ColorNumerics.From8BitTo16Bit(source.L), ColorNumerics.From8BitTo16Bit(source.L)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromLa32(La32 source) => new(source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgb24(Rgb24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgba32(Rgba32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgb48(Rgb48 source) => new(source.R, source.G); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromRgba64(Rgba64 source) => new(source.R, source.G); /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new Vector2(this.PackedValue & 0xFFFF, (this.PackedValue >> 16) & 0xFFFF) / Max; /// public override readonly bool Equals(object? obj) => obj is Rg32 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rg32 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"Rg32({vector.X:#0.##}, {vector.Y:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector = Vector2.Clamp(vector, Vector2.Zero, Vector2.One) * Max; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index 008de06bfb..fc54accfd5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -14,43 +15,36 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// +/// +/// Initializes a new instance of the struct. +/// +/// The red component. +/// The green component. +/// The blue component. [StructLayout(LayoutKind.Explicit)] -public partial struct Rgb24 : IPixel +[method: MethodImpl(MethodImplOptions.AggressiveInlining)] +public partial struct Rgb24(byte r, byte g, byte b) : IPixel { /// /// The red component. /// [FieldOffset(0)] - public byte R; + public byte R = r; /// /// The green component. /// [FieldOffset(1)] - public byte G; + public byte G = g; /// /// The blue component. /// [FieldOffset(2)] - public byte B; + public byte B = b; - private static readonly Vector4 MaxBytes = new(byte.MaxValue); - private static readonly Vector4 Half = new(0.5F); - - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] - public Rgb24(byte r, byte g, byte b) - { - this.R = r; - this.G = g; - this.B = b; - } + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Allows the implicit conversion of an instance of to a @@ -58,15 +52,8 @@ public partial struct Rgb24 : IPixel /// /// The instance of to convert. /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgb24(ColorSpaces.Rgb color) - { - var vector = new Vector4(color.ToVector3(), 1F); - - Rgb24 rgb = default; - rgb.FromScaledVector4(vector); - return rgb; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgb24(ColorSpaces.Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1f)); /// /// Compares two objects for equality. @@ -76,7 +63,7 @@ public partial struct Rgb24 : IPixel /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgb24 left, Rgb24 right) => left.Equals(right); /// @@ -87,9 +74,17 @@ public partial struct Rgb24 : IPixel /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -100,163 +95,103 @@ public partial struct Rgb24 : IPixel /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromVector4(Vector4 source) + { + source *= MaxBytes; + source += Half; + source = Numerics.Clamp(source, Vector4.Zero, MaxBytes); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Rgba32(this.R, this.G, this.B, byte.MaxValue).ToVector4(); + Vector128 result = Vector128.ConvertToInt32(source.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8)); + } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromLa16(La16 source) => new(source.L, source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source.Rgb; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B) + }; /// public override readonly bool Equals(object? obj) => obj is Rgb24 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgb24 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.B, this.G); /// public override readonly string ToString() => $"Rgb24({this.R}, {this.G}, {this.B})"; - - /// - /// Packs a into a color. - /// - /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) - { - vector *= MaxBytes; - vector += Half; - vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index ae4d6dc011..af901e3d28 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -55,7 +55,7 @@ public partial struct Rgb48 : IPixel /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgb48 left, Rgb48 right) => left.Equals(right); /// @@ -66,9 +66,22 @@ public partial struct Rgb48 : IPixel /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb48 left, Rgb48 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + => new(ColorNumerics.From16BitTo8Bit(this.R), ColorNumerics.From16BitTo8Bit(this.G), ColorNumerics.From16BitTo8Bit(this.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.R / Max, this.G / Max, this.B / Max, 1f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -80,152 +93,88 @@ public partial struct Rgb48 : IPixel public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromVector4(Vector4 source) { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One) * Max; + return new((ushort)MathF.Round(source.X), (ushort)MathF.Round(source.Y), (ushort)MathF.Round(source.Z)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.R / Max, this.G / Max, this.B / Max, 1F); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromArgb32(Argb32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgr24(Bgr24 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgra32(Bgra32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this = source.Rgb; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromL8(L8 source) { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; + ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromL16(L16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromLa16(La16 source) { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; + ushort rgb = ColorNumerics.From8BitTo16Bit(source.L); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromLa32(La32 source) => new(source.L, source.L, source.L); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgb24(Rgb24 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgba32(Rgba32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - dest.G = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - dest.B = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - dest.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromAbgr32(Abgr32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this = source; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); /// public override readonly bool Equals(object? obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgb48 other) => this.R.Equals(other.R) && this.G.Equals(other.G) && this.B.Equals(other.B); /// public override readonly string ToString() => $"Rgb48({this.R}, {this.G}, {this.B})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => HashCode.Combine(this.R, this.G, this.B); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index ac1eedb072..85ae045a09 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -13,7 +13,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -public partial struct Rgba1010102 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct Rgba1010102(Vector4 vector) : IPixel, IPackedVector { private static readonly Vector4 Multiplier = new(1023F, 1023F, 1023F, 3F); @@ -29,14 +33,8 @@ public partial struct Rgba1010102 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public uint PackedValue { get; set; } + public uint PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -46,7 +44,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba1010102 left, Rgba1010102 right) => left.Equals(right); /// @@ -57,33 +55,15 @@ public partial struct Rgba1010102 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 10, 10, 10, 2), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() => new Vector4( (this.PackedValue >> 0) & 0x03FF, (this.PackedValue >> 10) & 0x03FF, @@ -91,81 +71,41 @@ public partial struct Rgba1010102 : IPixel, IPackedVector (this.PackedValue >> 30) & 0x03) / Multiplier; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 10, 10, 10, 2), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; /// public override readonly bool Equals(object? obj) => obj is Rgba1010102 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba1010102 other) => this.PackedValue == other.PackedValue; /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Rgba1010102({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); - [MethodImpl(InliningOptions.ShortMethod)] - private static uint Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static uint Pack(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Multiplier; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 8b2a078db6..83c376c9f6 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -6,6 +6,7 @@ using System.Globalization; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats; @@ -43,8 +44,8 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public byte A; - private static readonly Vector4 MaxBytes = new(byte.MaxValue); - private static readonly Vector4 Half = new(0.5F); + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// /// Initializes a new instance of the struct. @@ -52,7 +53,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The red component. /// The green component. /// The blue component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(byte r, byte g, byte b) { this.R = r; @@ -68,7 +69,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(byte r, byte g, byte b, byte a) { this.R = r; @@ -84,9 +85,9 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(float r, float g, float b, float a = 1) - : this() => this.Pack(r, g, b, a); + : this() => Pack(r, g, b, a); /// /// Initializes a new instance of the struct. @@ -94,9 +95,9 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector3 vector) - : this() => this.Pack(ref vector); + : this() => Pack(vector); /// /// Initializes a new instance of the struct. @@ -104,9 +105,9 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// The vector containing the components for the packed vector. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector4 vector) - : this() => this = PackNew(ref vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -114,7 +115,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// The packed value. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(uint packed) : this() => this.Rgba = packed; @@ -123,10 +124,10 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public uint Rgba { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -135,10 +136,10 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public Rgb24 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => new(this.R, this.G, this.B); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.R = value.R; @@ -152,10 +153,10 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public Bgr24 Bgr { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => new(this.R, this.G, this.B); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set { this.R = value.R; @@ -167,10 +168,10 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public uint PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => this.Rgba; - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => this.Rgba = value; } @@ -180,15 +181,8 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// The instance of to convert. /// An instance of . - [MethodImpl(InliningOptions.ShortMethod)] - public static implicit operator Rgba32(ColorSpaces.Rgb color) - { - var vector = new Vector4(color.ToVector3(), 1F); - - Rgba32 rgba = default; - rgba.FromScaledVector4(vector); - return rgba; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static implicit operator Rgba32(ColorSpaces.Rgb color) => FromScaledVector4(new Vector4(color.ToVector3(), 1F)); /// /// Compares two objects for equality. @@ -198,7 +192,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba32 left, Rgba32 right) => left.Equals(right); /// @@ -209,7 +203,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba32 left, Rgba32 right) => !left.Equals(right); /// @@ -224,7 +218,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The . /// /// Hexadecimal string is not in the correct format. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgba32 ParseHex(string hex) { Guard.NotNull(hex, nameof(hex)); @@ -249,7 +243,7 @@ public partial struct Rgba32 : IPixel, IPackedVector /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(string? hex, out Rgba32 result) { result = default; @@ -270,6 +264,18 @@ public partial struct Rgba32 : IPixel, IPackedVector return true; } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => this; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -281,140 +287,82 @@ public partial struct Rgba32 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.Pack(ref vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromVector4(Vector4 source) => Pack(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.Bgr = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) - { - this.R = source.R; - this.G = source.G; - this.B = source.B; - this.A = source.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromL8(L8 source) => new(source.PackedValue, source.PackedValue, source.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromL16(L16 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = byte.MaxValue; + byte rgb = ColorNumerics.From16BitTo8Bit(source.PackedValue); + return new(rgb, rgb, rgb); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromLa16(La16 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromLa32(La32 source) { - byte rgb = ColorNumerics.DownScaleFrom16BitTo8Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); + byte rgb = ColorNumerics.From16BitTo8Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From16BitTo8Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.Rgb = source; - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this = source; - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest = this; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = byte.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgb48(Rgb48 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = byte.MaxValue + }; /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) - { - this.R = ColorNumerics.DownScaleFrom16BitTo8Bit(source.R); - this.G = ColorNumerics.DownScaleFrom16BitTo8Bit(source.G); - this.B = ColorNumerics.DownScaleFrom16BitTo8Bit(source.B); - this.A = ColorNumerics.DownScaleFrom16BitTo8Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromRgba64(Rgba64 source) + => new() + { + R = ColorNumerics.From16BitTo8Bit(source.R), + G = ColorNumerics.From16BitTo8Bit(source.G), + B = ColorNumerics.From16BitTo8Bit(source.B), + A = ColorNumerics.From16BitTo8Bit(source.A) + }; /// /// Converts the value of this instance to a hexadecimal string. @@ -430,31 +378,14 @@ public partial struct Rgba32 : IPixel, IPackedVector public override readonly bool Equals(object? obj) => obj is Rgba32 rgba32 && this.Equals(rgba32); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba32 other) => this.Rgba.Equals(other.Rgba); /// public override readonly string ToString() => $"Rgba32({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.Rgba.GetHashCode(); - /// - /// Packs a into a color returning a new instance as a result. - /// - /// The vector containing the values to pack. - /// The - [MethodImpl(InliningOptions.ShortMethod)] - private static Rgba32 PackNew(ref Vector4 vector) - { - vector *= MaxBytes; - vector += Half; - vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - - return new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, (byte)vector.W); - } - /// /// Packs the four floats into a color. /// @@ -462,39 +393,29 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The y-component /// The z-component /// The w-component - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(float x, float y, float z, float w) - { - var value = new Vector4(x, y, z, w); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Rgba32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); /// /// Packs a into a uint. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector3 vector) - { - var value = new Vector4(vector, 1F); - this.Pack(ref value); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Rgba32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1f)); /// /// Packs a into a color. /// /// The vector containing the values to pack. - [MethodImpl(InliningOptions.ShortMethod)] - private void Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static Rgba32 Pack(Vector4 vector) { vector *= MaxBytes; vector += Half; vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - this.R = (byte)vector.X; - this.G = (byte)vector.Y; - this.B = (byte)vector.Z; - this.A = (byte)vector.W; + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } /// @@ -526,10 +447,10 @@ public partial struct Rgba32 : IPixel, IPackedVector return null; } - char r = hex[0]; - char g = hex[1]; - char b = hex[2]; char a = hex.Length == 3 ? 'F' : hex[3]; + char b = hex[2]; + char g = hex[1]; + char r = hex[0]; return new string(new[] { r, r, g, g, b, b, a, a }); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index b71ec5f353..5294064eb1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -45,7 +45,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// The green component. /// The blue component. /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(ushort r, ushort g, ushort b, ushort a) { this.R = r; @@ -58,64 +58,64 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in RGBA byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Rgba32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in BGRA byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Bgra32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in ARGB byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Argb32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 4 bytes in ABGR byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Abgr32 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); + this.A = ColorNumerics.From8BitTo16Bit(source.A); } /// /// Initializes a new instance of the struct. /// /// A structure of 3 bytes in RGB byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Rgb24 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); this.A = ushort.MaxValue; } @@ -123,12 +123,12 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Initializes a new instance of the struct. /// /// A structure of 3 bytes in BGR byte order. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Bgr24 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); + this.R = ColorNumerics.From8BitTo16Bit(source.R); + this.G = ColorNumerics.From8BitTo16Bit(source.G); + this.B = ColorNumerics.From8BitTo16Bit(source.B); this.A = ushort.MaxValue; } @@ -136,7 +136,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Initializes a new instance of the struct. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba64(Vector4 vector) { vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; @@ -151,20 +151,20 @@ public partial struct Rgba64 : IPixel, IPackedVector /// public Rgb48 Rgb { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } /// public ulong PackedValue { - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] readonly get => Unsafe.As(ref Unsafe.AsRef(in this)); - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] set => Unsafe.As(ref this) = value; } @@ -176,7 +176,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Rgba64 left, Rgba64 right) => left.PackedValue == right.PackedValue; /// @@ -187,9 +187,26 @@ public partial struct Rgba64 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba64 left, Rgba64 right) => left.PackedValue != right.PackedValue; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() + => new( + ColorNumerics.From16BitTo8Bit(this.R), + ColorNumerics.From16BitTo8Bit(this.G), + ColorNumerics.From16BitTo8Bit(this.B), + ColorNumerics.From16BitTo8Bit(this.A)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -201,181 +218,80 @@ public partial struct Rgba64 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One) * Max; - this.R = (ushort)MathF.Round(vector.X); - this.G = (ushort)MathF.Round(vector.Y); - this.B = (ushort)MathF.Round(vector.Z); - this.A = (ushort)MathF.Round(vector.W); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromVector4(Vector4 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / Max; + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromArgb32(Argb32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromBgr24(Bgr24 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromBgra32(Bgra32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromAbgr32(Abgr32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromL8(L8 source) { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort rgb = ColorNumerics.From8BitTo16Bit(source.PackedValue); + return new(rgb, rgb, rgb, ushort.MaxValue); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) - { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.PackedValue); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ushort.MaxValue; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) - { - this.R = source.PackedValue; - this.G = source.PackedValue; - this.B = source.PackedValue; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromL16(L16 source) => new(source.PackedValue, source.PackedValue, source.PackedValue, ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromLa16(La16 source) { - ushort rgb = ColorNumerics.UpscaleFrom8BitTo16Bit(source.L); - this.R = rgb; - this.G = rgb; - this.B = rgb; - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); + ushort rgb = ColorNumerics.From8BitTo16Bit(source.L); + return new(rgb, rgb, rgb, ColorNumerics.From8BitTo16Bit(source.A)); } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) - { - this.R = source.L; - this.G = source.L; - this.B = source.L; - this.A = source.A; - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromLa32(La32 source) => new(source.L, source.L, source.L, source.A); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) - { - this.R = ColorNumerics.UpscaleFrom8BitTo16Bit(source.R); - this.G = ColorNumerics.UpscaleFrom8BitTo16Bit(source.G); - this.B = ColorNumerics.UpscaleFrom8BitTo16Bit(source.B); - this.A = ColorNumerics.UpscaleFrom8BitTo16Bit(source.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgb24(Rgb24 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) - { - dest.R = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - dest.G = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - dest.B = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - dest.A = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgba32(Rgba32 source) => new(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) - { - this.Rgb = source; - this.A = ushort.MaxValue; - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B, ushort.MaxValue); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this = source; - - /// - /// Convert to . - /// - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Rgba32 ToRgba32() - { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); - return new Rgba32(r, g, b, a); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B, source.A); /// /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Bgra32 ToBgra32() { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); + byte r = ColorNumerics.From16BitTo8Bit(this.R); + byte g = ColorNumerics.From16BitTo8Bit(this.G); + byte b = ColorNumerics.From16BitTo8Bit(this.B); + byte a = ColorNumerics.From16BitTo8Bit(this.A); return new Bgra32(r, g, b, a); } @@ -383,13 +299,13 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Argb32 ToArgb32() { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); + byte r = ColorNumerics.From16BitTo8Bit(this.R); + byte g = ColorNumerics.From16BitTo8Bit(this.G); + byte b = ColorNumerics.From16BitTo8Bit(this.B); + byte a = ColorNumerics.From16BitTo8Bit(this.A); return new Argb32(r, g, b, a); } @@ -397,13 +313,13 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Abgr32 ToAbgr32() { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); - byte a = ColorNumerics.DownScaleFrom16BitTo8Bit(this.A); + byte r = ColorNumerics.From16BitTo8Bit(this.R); + byte g = ColorNumerics.From16BitTo8Bit(this.G); + byte b = ColorNumerics.From16BitTo8Bit(this.B); + byte a = ColorNumerics.From16BitTo8Bit(this.A); return new Abgr32(r, g, b, a); } @@ -411,12 +327,12 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Rgb24 ToRgb24() { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); + byte r = ColorNumerics.From16BitTo8Bit(this.R); + byte g = ColorNumerics.From16BitTo8Bit(this.G); + byte b = ColorNumerics.From16BitTo8Bit(this.B); return new Rgb24(r, g, b); } @@ -424,12 +340,12 @@ public partial struct Rgba64 : IPixel, IPackedVector /// Convert to . /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Bgr24 ToBgr24() { - byte r = ColorNumerics.DownScaleFrom16BitTo8Bit(this.R); - byte g = ColorNumerics.DownScaleFrom16BitTo8Bit(this.G); - byte b = ColorNumerics.DownScaleFrom16BitTo8Bit(this.B); + byte r = ColorNumerics.From16BitTo8Bit(this.R); + byte g = ColorNumerics.From16BitTo8Bit(this.G); + byte b = ColorNumerics.From16BitTo8Bit(this.B); return new Bgr24(r, g, b); } @@ -437,13 +353,11 @@ public partial struct Rgba64 : IPixel, IPackedVector public override readonly bool Equals(object? obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Rgba64 other) => this.PackedValue.Equals(other.PackedValue); /// public override readonly string ToString() => $"Rgba64({this.R}, {this.G}, {this.B}, {this.A})"; /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index cd61b13b24..0511f32794 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -19,49 +19,41 @@ namespace SixLabors.ImageSharp.PixelFormats; /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// +/// +/// Initializes a new instance of the struct. +/// +/// The red component. +/// The green component. +/// The blue component. +/// The alpha component. [StructLayout(LayoutKind.Sequential)] -public partial struct RgbaVector : IPixel +[method: MethodImpl(MethodImplOptions.AggressiveInlining)] +public partial struct RgbaVector(float r, float g, float b, float a = 1) : IPixel { /// /// Gets or sets the red component. /// - public float R; + public float R = r; /// /// Gets or sets the green component. /// - public float G; + public float G = g; /// /// Gets or sets the blue component. /// - public float B; + public float B = b; /// /// Gets or sets the alpha component. /// - public float A; + public float A = a; private const float MaxBytes = byte.MaxValue; private static readonly Vector4 Max = new(MaxBytes); private static readonly Vector4 Half = new(0.5F); - /// - /// Initializes a new instance of the struct. - /// - /// The red component. - /// The green component. - /// The blue component. - /// The alpha component. - [MethodImpl(InliningOptions.ShortMethod)] - public RgbaVector(float r, float g, float b, float a = 1) - { - this.R = r; - this.G = g; - this.B = b; - this.A = a; - } - /// /// Compares two objects for equality. /// @@ -70,7 +62,7 @@ public partial struct RgbaVector : IPixel /// /// True if the parameter is equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(RgbaVector left, RgbaVector right) => left.Equals(right); /// @@ -81,20 +73,16 @@ public partial struct RgbaVector : IPixel /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); - /// - /// Creates a new instance of the struct. - /// - /// - /// The hexadecimal representation of the combined color components arranged - /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. - /// - /// - /// The . - /// - public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A); /// public static PixelTypeInfo GetPixelTypeInfo() @@ -107,83 +95,28 @@ public partial struct RgbaVector : IPixel public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromVector4(Vector4 source) { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); - this.R = vector.X; - this.G = vector.Y; - this.B = vector.Z; - this.A = vector.W; + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z, source.W); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new(this.R, this.G, this.B, this.A); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + /// Creates a new instance of the struct. + /// + /// + /// The hexadecimal representation of the combined color components arranged + /// in rgb, rgba, rrggbb, or rrggbbaa format to match web syntax. + /// + /// + /// The . + /// + public static RgbaVector FromHex(string hex) => Color.ParseHex(hex).ToPixel(); /// /// Converts the value of this instance to a hexadecimal string. @@ -202,7 +135,6 @@ public partial struct RgbaVector : IPixel public override readonly bool Equals(object? obj) => obj is RgbaVector other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(RgbaVector other) => this.R.Equals(other.R) && this.G.Equals(other.G) diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index c8819337ed..e2b652d1a8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-32767, -32767, 0, 1] to [32767, 32767, 0, 1] in vector form. /// /// -public partial struct Short2 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// The vector containing the component values. +public partial struct Short2(Vector2 vector) : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -33,14 +37,8 @@ public partial struct Short2 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// The vector containing the component values. - public Short2(Vector2 vector) => this.PackedValue = Pack(vector); - /// - public uint PackedValue { get; set; } + public uint PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -50,7 +48,7 @@ public partial struct Short2 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Short2 left, Short2 right) => left.Equals(right); /// @@ -61,9 +59,23 @@ public partial struct Short2 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Short2 left, Short2 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() + { + Vector2 scaled = this.ToVector2(); + scaled += new Vector2(32767f); + scaled /= 65534F; + return new Vector4(scaled, 0f, 1f); + } + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0f, 1f); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -75,119 +87,43 @@ public partial struct Short2 : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromScaledVector4(Vector4 source) { - Vector2 scaled = new Vector2(vector.X, vector.Y) * 65534F; + Vector2 scaled = new Vector2(source.X, source.Y) * 65534F; scaled -= new Vector2(32767F); - this.PackedValue = Pack(scaled); + return new() { PackedValue = Pack(scaled) }; } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() - { - var scaled = this.ToVector2(); - scaled += new Vector2(32767F); - scaled /= 65534F; - return new Vector4(scaled, 0F, 1F); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) - { - var vector2 = new Vector2(vector.X, vector.Y); - this.PackedValue = Pack(vector2); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10), 0, 1); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. /// /// The . - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector2 ToVector2() => new((short)(this.PackedValue & 0xFFFF), (short)(this.PackedValue >> 0x10)); /// public override readonly bool Equals(object? obj) => obj is Short2 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Short2 other) => this.PackedValue.Equals(other.PackedValue); /// - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector2(); + Vector2 vector = this.ToVector2(); return FormattableString.Invariant($"Short2({vector.X:#0.##}, {vector.Y:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private static uint Pack(Vector2 vector) { vector = Vector2.Clamp(vector, Min, Max); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index cfd9ce0bfb..18d7f22ec5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -12,7 +12,11 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-37267, -37267, -37267, -37267] to [37267, 37267, 37267, 37267] in vector form. /// /// -public partial struct Short4 : IPixel, IPackedVector +/// +/// Initializes a new instance of the struct. +/// +/// A vector containing the initial values for the components. +public partial struct Short4(Vector4 vector) : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -20,8 +24,8 @@ public partial struct Short4 : IPixel, IPackedVector // Two's complement private const float MinNeg = ~(int)MaxPos; - private static readonly Vector4 Max = new Vector4(MaxPos); - private static readonly Vector4 Min = new Vector4(MinNeg); + private static readonly Vector4 Max = new(MaxPos); + private static readonly Vector4 Min = new(MinNeg); /// /// Initializes a new instance of the struct. @@ -35,14 +39,8 @@ public partial struct Short4 : IPixel, IPackedVector { } - /// - /// Initializes a new instance of the struct. - /// - /// A vector containing the initial values for the components. - public Short4(Vector4 vector) => this.PackedValue = Pack(ref vector); - /// - public ulong PackedValue { get; set; } + public ulong PackedValue { get; set; } = Pack(vector); /// /// Compares two objects for equality. @@ -52,7 +50,7 @@ public partial struct Short4 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Short4 left, Short4 right) => left.Equals(right); /// @@ -63,139 +61,75 @@ public partial struct Short4 : IPixel, IPackedVector /// /// True if the parameter is not equal to the parameter; otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Short4 left, Short4 right) => !left.Equals(right); - /// - public static PixelTypeInfo GetPixelTypeInfo() - => PixelTypeInfo.Create( - PixelComponentInfo.Create(4, 16, 16, 16, 16), - PixelColorType.RGB | PixelColorType.Alpha, - PixelAlphaRepresentation.Unassociated); - - /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) - { - vector *= 65534F; - vector -= new Vector4(32767F); - this.FromVector4(vector); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { - var scaled = this.ToVector4(); - scaled += new Vector4(32767F); - scaled /= 65534F; + Vector4 scaled = this.ToVector4(); + scaled += new Vector4(32767f); + scaled /= 65534f; return scaled; } /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) => this.PackedValue = Pack(ref vector); - - /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToVector4() - { - return new Vector4( + => new( (short)(this.PackedValue & 0xFFFF), (short)((this.PackedValue >> 0x10) & 0xFFFF), (short)((this.PackedValue >> 0x20) & 0xFFFF), (short)((this.PackedValue >> 0x30) & 0xFFFF)); - } - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + public static PixelTypeInfo GetPixelTypeInfo() + => PixelTypeInfo.Create( + PixelComponentInfo.Create(4, 16, 16, 16, 16), + PixelColorType.RGB | PixelColorType.Alpha, + PixelAlphaRepresentation.Unassociated); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromScaledVector4(Vector4 source) { - dest.FromScaledVector4(this.ToScaledVector4()); + source *= 65534F; + source -= new Vector4(32767F); + return FromVector4(source); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromVector4(Vector4 source) => new(source); /// public override readonly bool Equals(object? obj) => obj is Short4 other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] public readonly bool Equals(Short4 other) => this.PackedValue.Equals(other.PackedValue); /// /// Gets the hash code for the current instance. /// /// Hash code for the instance. - [MethodImpl(InliningOptions.ShortMethod)] public override readonly int GetHashCode() => this.PackedValue.GetHashCode(); /// public override readonly string ToString() { - var vector = this.ToVector4(); + Vector4 vector = this.ToVector4(); return FormattableString.Invariant($"Short4({vector.X:#0.##}, {vector.Y:#0.##}, {vector.Z:#0.##}, {vector.W:#0.##})"); } - [MethodImpl(InliningOptions.ShortMethod)] - private static ulong Pack(ref Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static ulong Pack(Vector4 vector) { - vector = Numerics.Clamp(vector, Min, Max); - // Clamp the value between min and max values + vector = Numerics.Clamp(vector, Min, Max); ulong word4 = ((ulong)Convert.ToInt32(Math.Round(vector.X)) & 0xFFFF) << 0x00; ulong word3 = ((ulong)Convert.ToInt32(Math.Round(vector.Y)) & 0xFFFF) << 0x10; ulong word2 = ((ulong)Convert.ToInt32(Math.Round(vector.Z)) & 0xFFFF) << 0x20; diff --git a/src/ImageSharp/PixelFormats/README.md b/src/ImageSharp/PixelFormats/README.md index cbebaf23ad..4c7ee545a2 100644 --- a/src/ImageSharp/PixelFormats/README.md +++ b/src/ImageSharp/PixelFormats/README.md @@ -1,4 +1,4 @@ -Pixel formats adapted and extended from: +Pixel formats adapted and extended from: https://github.com/MonoGame/MonoGame diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 8d16849825..479079a80c 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -117,12 +117,26 @@ public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_Conv } } - /* Method | Count | Mean | Error | StdDev | Scaled | ScaledSD | - ---------- |------ |---------:|---------:|---------:|-------:|---------:| - ByRef | 256 | 128.5 ns | 1.217 ns | 1.138 ns | 1.00 | 0.00 | - ByVal | 256 | 196.7 ns | 2.792 ns | 2.612 ns | 1.53 | 0.02 | - FromBytes | 256 | 321.7 ns | 2.180 ns | 1.820 ns | 2.50 | 0.03 | - Inline | 256 | 129.9 ns | 2.759 ns | 2.581 ns | 1.01 | 0.02 | */ + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.100 + [Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | + |---------- |------ |-----------:|--------:|--------:|------:| + | ByRef | 256 | 102.5 ns | 0.44 ns | 0.39 ns | 1.00 | + | ByVal | 256 | 102.2 ns | 0.30 ns | 0.25 ns | 1.00 | + | FromBytes | 256 | 200.5 ns | 1.01 ns | 0.90 ns | 1.96 | + | Inline | 256 | 107.0 ns | 0.90 ns | 0.84 ns | 1.04 | + | | | | | | | + | ByRef | 2048 | 770.8 ns | 3.22 ns | 2.86 ns | 1.00 | + | ByVal | 2048 | 770.3 ns | 2.05 ns | 1.92 ns | 1.00 | + | FromBytes | 2048 | 1,546.8 ns | 7.51 ns | 6.66 ns | 2.01 | + | Inline | 2048 | 797.6 ns | 2.90 ns | 2.26 ns | 1.03 | + */ } public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 337d02084a..447433dabe 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -114,7 +114,7 @@ public class L16Tests // Arrange L16 gray = default; const byte rgb = 128; - ushort scaledRgb = ColorNumerics.UpscaleFrom8BitTo16Bit(rgb); + ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act @@ -132,7 +132,7 @@ public class L16Tests public void L16_ToRgba32(ushort input) { // Arrange - ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); + ushort expected = ColorNumerics.From16BitTo8Bit(input); L16 gray = new(input); // Act diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index f55707c05b..57b70f7843 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -118,7 +118,7 @@ public class La32Tests // Arrange La32 gray = default; const byte rgb = 128; - ushort scaledRgb = ColorNumerics.UpscaleFrom8BitTo16Bit(rgb); + ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act @@ -137,7 +137,7 @@ public class La32Tests public void La32_ToRgba32(ushort input) { // Arrange - ushort expected = ColorNumerics.DownScaleFrom16BitTo8Bit(input); + ushort expected = ColorNumerics.From16BitTo8Bit(input); La32 gray = new(input, ushort.MaxValue); // Act diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs index 006cb9eb61..4134922816 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs @@ -104,7 +104,7 @@ public abstract partial class PixelConverterTests { ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); ref L16 dp = ref Unsafe.Add(ref l16Ref, i); - dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); + dp.Pack(sp.ToScaledVector4()); } return; From dfd983f17c6975aaad6877a74a945ff71ca23b0e Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 20 Jan 2024 20:59:33 +1000 Subject: [PATCH 131/219] Update library to use new pixel API --- src/ImageSharp.ruleset | 5 +- src/ImageSharp/Color/Color.cs | 15 +- src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs | 210 +++--- src/ImageSharp/Formats/Gif/GifDecoderCore.cs | 10 +- src/ImageSharp/Formats/Gif/GifEncoderCore.cs | 7 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 9 +- .../Formats/Png/PngScanlineProcessor.cs | 119 +-- src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs | 14 +- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 100 ++- src/ImageSharp/Formats/Tga/TgaEncoderCore.cs | 10 +- .../Tiff/Compression/HorizontalPredictor.cs | 140 ++-- .../BlackIsZero16TiffColor{TPixel}.cs | 10 +- .../BlackIsZero1TiffColor{TPixel}.cs | 6 +- .../BlackIsZero24TiffColor{TPixel}.cs | 12 +- .../BlackIsZero32FloatTiffColor{TPixel}.cs | 11 +- .../BlackIsZero32TiffColor{TPixel}.cs | 13 +- .../BlackIsZero4TiffColor{TPixel}.cs | 25 +- .../BlackIsZeroTiffColor{TPixel}.cs | 13 +- .../CieLabPlanarTiffColor{TPixel}.cs | 11 +- .../CieLabTiffColor{TPixel}.cs | 10 +- .../CmykTiffColor{TPixel}.cs | 8 +- .../PaletteTiffColor{TPixel}.cs | 13 +- .../Rgb161616TiffColor{TPixel}.cs | 15 +- .../Rgb16PlanarTiffColor{TPixel}.cs | 22 +- .../Rgb242424TiffColor{TPixel}.cs | 20 +- .../Rgb24PlanarTiffColor{TPixel}.cs | 20 +- .../Rgb323232TiffColor{TPixel}.cs | 20 +- .../Rgb32PlanarTiffColor{TPixel}.cs | 21 +- .../Rgb444TiffColor{TPixel}.cs | 12 +- .../RgbFloat323232TiffColor{TPixel}.cs | 12 +- .../RgbPlanarTiffColor{TPixel}.cs | 13 +- .../RgbTiffColor{TPixel}.cs | 8 +- .../Rgba16161616TiffColor{TPixel}.cs | 23 +- .../Rgba16PlanarTiffColor{TPixel}.cs | 34 +- .../Rgba24242424TiffColor{TPixel}.cs | 33 +- .../Rgba24PlanarTiffColor{TPixel}.cs | 32 +- .../Rgba32323232TiffColor{TPixel}.cs | 33 +- .../Rgba32PlanarTiffColor{TPixel}.cs | 34 +- .../Rgba8888TiffColor{TPixel}.cs | 5 +- .../RgbaFloat32323232TiffColor{TPixel}.cs | 12 +- .../RgbaPlanarTiffColor{TPixel}.cs | 18 +- .../RgbaTiffColor{TPixel}.cs | 12 +- .../WhiteIsZero16TiffColor{TPixel}.cs | 14 +- .../WhiteIsZero1TiffColor{TPixel}.cs | 7 +- .../WhiteIsZero24TiffColor{TPixel}.cs | 12 +- .../WhiteIsZero32FloatTiffColor{TPixel}.cs | 11 +- .../WhiteIsZero32TiffColor{TPixel}.cs | 12 +- .../WhiteIsZero4TiffColor{TPixel}.cs | 25 +- .../WhiteIsZero8TiffColor{TPixel}.cs | 8 +- .../WhiteIsZeroTiffColor{TPixel}.cs | 12 +- .../YCbCrPlanarTiffColor{TPixel}.cs | 12 +- .../YCbCrTiffColor{TPixel}.cs | 11 +- .../Formats/Tiff/TiffDecoderCore.cs | 6 +- .../Formats/Tiff/Utils/TiffUtilities.cs | 120 ++++ .../Formats/Tiff/Utils/TiffUtils.cs | 176 ----- .../Formats/Webp/Lossy/WebpLossyDecoder.cs | 4 +- src/ImageSharp/PixelFormats/IPixel.cs | 40 +- .../DefaultPixelBlenders.Generated.cs | 432 +++-------- .../DefaultPixelBlenders.Generated.tt | 4 +- .../PorterDuffFunctions.Generated.cs | 432 +++-------- .../PorterDuffFunctions.Generated.tt | 4 +- .../PixelFormats/PixelConversionModifiers.cs | 8 +- .../PixelFormats/PixelImplementations/A8.cs | 12 +- .../PixelImplementations/Abgr32.cs | 20 +- .../PixelImplementations/Argb32.cs | 41 +- .../PixelImplementations/Bgr24.cs | 43 +- .../PixelImplementations/Bgr565.cs | 55 ++ .../PixelImplementations/Bgra32.cs | 10 +- .../PixelImplementations/Bgra4444.cs | 70 +- .../PixelImplementations/Bgra5551.cs | 72 +- .../PixelImplementations/Byte4.cs | 80 ++- .../PixelImplementations/HalfSingle.cs | 70 +- .../PixelImplementations/HalfVector2.cs | 56 ++ .../PixelImplementations/HalfVector4.cs | 74 +- .../PixelFormats/PixelImplementations/L16.cs | 26 +- .../PixelFormats/PixelImplementations/L8.cs | 29 +- .../PixelFormats/PixelImplementations/La16.cs | 34 +- .../PixelFormats/PixelImplementations/La32.cs | 40 +- .../PixelImplementations/NormalizedByte2.cs | 70 +- .../PixelImplementations/NormalizedByte4.cs | 70 +- .../PixelImplementations/NormalizedShort2.cs | 70 +- .../PixelImplementations/NormalizedShort4.cs | 70 +- .../PixelOperations/A8.PixelOperations.cs | 2 - .../PixelOperations/Abgr32.PixelOperations.cs | 2 - .../PixelOperations/Argb32.PixelOperations.cs | 2 - .../PixelOperations/Bgr24.PixelOperations.cs | 2 - .../PixelOperations/Bgr565.PixelOperations.cs | 2 - .../PixelOperations/Bgra32.PixelOperations.cs | 2 - .../Bgra4444.PixelOperations.cs | 2 - .../Bgra5551.PixelOperations.cs | 2 - .../PixelOperations/Byte4.PixelOperations.cs | 2 - .../Abgr32.PixelOperations.Generated.cs | 267 ++++--- .../Argb32.PixelOperations.Generated.cs | 267 ++++--- .../Bgr24.PixelOperations.Generated.cs | 267 ++++--- .../Bgra32.PixelOperations.Generated.cs | 267 ++++--- .../Bgra5551.PixelOperations.Generated.cs | 222 +++--- .../L16.PixelOperations.Generated.cs | 222 +++--- .../Generated/L8.PixelOperations.Generated.cs | 222 +++--- .../La16.PixelOperations.Generated.cs | 222 +++--- .../La32.PixelOperations.Generated.cs | 222 +++--- .../Rgb24.PixelOperations.Generated.cs | 267 ++++--- .../Rgb48.PixelOperations.Generated.cs | 222 +++--- .../Rgba32.PixelOperations.Generated.cs | 257 +++---- .../Rgba64.PixelOperations.Generated.cs | 222 +++--- .../Generated/_Common.ttinclude | 69 +- .../HalfSingle.PixelOperations.cs | 2 - .../HalfVector2.PixelOperations.cs | 2 - .../HalfVector4.PixelOperations.cs | 2 - .../PixelOperations/L16.PixelOperations.cs | 2 - .../PixelOperations/L8.PixelOperations.cs | 2 - .../PixelOperations/La16.PixelOperations.cs | 2 - .../PixelOperations/La32.PixelOperations.cs | 2 - .../NormalizedByte2.PixelOperations.cs | 2 - .../NormalizedByte4.PixelOperations.cs | 2 - .../NormalizedShort2.PixelOperations.cs | 2 - .../NormalizedShort4.PixelOperations.cs | 2 - .../PixelOperations/Rg32.PixelOperations.cs | 2 - .../PixelOperations/Rgb24.PixelOperations.cs | 2 - .../PixelOperations/Rgb48.PixelOperations.cs | 2 - .../PixelOperations/Rgba32.PixelOperations.cs | 1 - .../PixelOperations/Rgba64.PixelOperations.cs | 2 - .../RgbaVector.PixelOperations.cs | 40 -- .../PixelOperations/Short2.PixelOperations.cs | 2 - .../PixelOperations/Short4.PixelOperations.cs | 2 - .../PixelFormats/PixelImplementations/Rg32.cs | 24 +- .../PixelImplementations/Rgb24.cs | 49 +- .../PixelImplementations/Rgb48.cs | 23 +- .../PixelImplementations/Rgba1010102.cs | 70 +- .../PixelImplementations/Rgba32.cs | 37 +- .../PixelImplementations/Rgba64.cs | 60 +- .../PixelImplementations/RgbaVector.cs | 90 ++- .../PixelImplementations/Short2.cs | 70 +- .../PixelImplementations/Short4.cs | 70 +- .../PixelOperations{TPixel}.Generated.cs | 676 ++++++++---------- .../PixelOperations{TPixel}.Generated.tt | 52 +- .../PixelFormats/PixelOperations{TPixel}.cs | 70 +- .../Utils/Vector4Converters.Default.cs | 92 +-- .../EdgeDetectorCompassProcessor{TPixel}.cs | 5 +- .../Processors/Dithering/ErrorDither.cs | 2 +- .../Processors/Dithering/OrderedDither.cs | 8 +- ...eHistogramEqualizationProcessor{TPixel}.cs | 25 +- ...alizationSlidingWindowProcessor{TPixel}.cs | 2 +- .../Quantization/EuclideanPixelMap{TPixel}.cs | 6 +- .../Quantization/OctreeQuantizer{TPixel}.cs | 7 +- .../Quantization/WuQuantizer{TPixel}.cs | 8 +- .../Bulk/FromRgba32Bytes.cs | 12 +- .../ImageSharp.Benchmarks/Bulk/FromVector4.cs | 10 +- .../Bulk/ToRgba32Bytes.cs | 3 +- .../PixelConversion_Rgba32_To_Argb32.cs | 44 +- .../PixelConversion_Rgba32_To_Bgra32.cs | 58 +- tests/ImageSharp.Tests/Color/RgbaDouble.cs | 141 ++-- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 22 +- .../Jpg/Utils/LibJpegTools.ComponentData.cs | 13 +- .../Jpg/Utils/LibJpegTools.SpectralData.cs | 43 +- .../Formats/Png/PngEncoderTests.cs | 2 +- .../Formats/WebP/PredictorEncoderTests.cs | 10 +- tests/ImageSharp.Tests/Issues/Issue594.cs | 168 +---- .../ImageSharp.Tests/PixelFormats/A8Tests.cs | 13 +- .../PixelFormats/Abgr32Tests.cs | 11 +- .../PixelFormats/Argb32Tests.cs | 20 +- .../PixelFormats/Bgr24Tests.cs | 11 +- .../PixelFormats/Bgr565Tests.cs | 65 +- .../PixelFormats/Bgra32Tests.cs | 11 +- .../PixelFormats/Bgra4444Tests.cs | 82 +-- .../PixelFormats/Bgra5551Tests.cs | 110 ++- .../PixelFormats/Byte4Tests.cs | 93 ++- .../PixelFormats/HalfSingleTests.cs | 15 +- .../PixelFormats/HalfVector2Tests.cs | 12 +- .../PixelFormats/HalfVector4Tests.cs | 16 +- .../ImageSharp.Tests/PixelFormats/L16Tests.cs | 35 +- .../ImageSharp.Tests/PixelFormats/L8Tests.cs | 70 +- .../PixelFormats/La16Tests.cs | 57 +- .../PixelFormats/La32Tests.cs | 43 +- .../PixelFormats/NormalizedByte2Tests.cs | 16 +- .../PixelFormats/NormalizedByte4Tests.cs | 65 +- .../PixelFormats/NormalizedShort2Tests.cs | 8 +- .../PixelFormats/NormalizedShort4Tests.cs | 63 +- ...ConverterTests.ReferenceImplementations.cs | 43 +- .../PixelOperations/PixelOperationsTests.cs | 206 +++--- .../PixelFormats/Rg32Tests.cs | 14 +- .../PixelFormats/Rgb24Tests.cs | 14 +- .../PixelFormats/Rgb48Tests.cs | 11 +- .../PixelFormats/Rgba1010102Tests.cs | 76 +- .../PixelFormats/Rgba32Tests.cs | 49 +- .../PixelFormats/Rgba64Tests.cs | 24 +- .../PixelFormats/RgbaVectorTests.cs | 27 +- .../PixelFormats/Short2Tests.cs | 29 +- .../PixelFormats/Short4Tests.cs | 54 +- .../PixelFormats/UnPackedPixelTests.cs | 6 +- .../Processing/IntegralImageTests.cs | 22 +- .../Transforms/AffineTransformTests.cs | 137 ++-- tests/ImageSharp.Tests/TestFormat.cs | 74 +- .../BasicTestPatternProvider.cs | 27 +- .../ImageProviders/TestPatternProvider.cs | 79 +- .../TestUtilities/ImagingTestCaseUtility.cs | 11 +- .../TestUtilities/TestImageExtensions.cs | 9 +- .../TestUtilities/TestPixel.cs | 9 +- .../TestUtilities/TestUtils.cs | 35 +- .../Tests/TestImageProviderTests.cs | 4 +- .../Tests/TestUtilityExtensionsTests.cs | 9 +- 200 files changed, 4803 insertions(+), 5794 deletions(-) create mode 100644 src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs delete mode 100644 src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index f29278c95f..72e0cd1b0f 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,6 +1,7 @@  - + + - + \ No newline at end of file diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 3b91a78d15..82ecab3909 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -248,15 +248,12 @@ public readonly partial struct Color : IEquatable [MethodImpl(InliningOptions.ShortMethod)] public string ToHex() { - Rgba32 rgba = default; if (this.boxedHighPrecisionPixel is not null) { - this.boxedHighPrecisionPixel.ToRgba32(ref rgba); - return rgba.ToHex(); + return this.boxedHighPrecisionPixel.ToRgba32().ToHex(); } - rgba.FromScaledVector4(this.data); - return rgba.ToHex(); + return Rgba32.FromScaledVector4(this.data).ToHex(); } /// @@ -278,14 +275,10 @@ public readonly partial struct Color : IEquatable if (this.boxedHighPrecisionPixel is null) { - pixel = default; - pixel.FromScaledVector4(this.data); - return pixel; + return TPixel.FromScaledVector4(this.data); } - pixel = default; - pixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); - return pixel; + return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); } /// diff --git a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs index 863fed359c..bed489752c 100644 --- a/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs +++ b/src/ImageSharp/Formats/Bmp/BmpDecoderCore.cs @@ -294,72 +294,60 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals private void ReadRle(BufferedReadStream stream, BmpCompression compression, Buffer2D pixels, byte[] colors, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { - TPixel color = default; - using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean)) + using IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean); + Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; + Span undefinedPixelsSpan = undefinedPixels.Memory.Span; + Span bufferSpan = buffer.Memory.Span; + if (compression is BmpCompression.RLE8) { - Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; - Span undefinedPixelsSpan = undefinedPixels.Memory.Span; - Span bufferSpan = buffer.Memory.Span; - if (compression is BmpCompression.RLE8) - { - this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - } - else - { - this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - } + this.UncompressRle8(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + } + else + { + this.UncompressRle4(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + } - for (int y = 0; y < height; y++) - { - int newY = Invert(y, height, inverted); - int rowStartIdx = y * width; - Span bufferRow = bufferSpan.Slice(rowStartIdx, width); - Span pixelRow = pixels.DangerousGetRowSpan(newY); + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + int rowStartIdx = y * width; + Span bufferRow = bufferSpan.Slice(rowStartIdx, width); + Span pixelRow = pixels.DangerousGetRowSpan(newY); - bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; - if (rowHasUndefinedPixels) + bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; + if (rowHasUndefinedPixels) + { + // Slow path with undefined pixels. + for (int x = 0; x < width; x++) { - // Slow path with undefined pixels. - for (int x = 0; x < width; x++) + byte colorIdx = bufferRow[x]; + if (undefinedPixelsSpan[rowStartIdx + x]) { - byte colorIdx = bufferRow[x]; - if (undefinedPixelsSpan[rowStartIdx + x]) - { - switch (this.rleSkippedPixelHandling) - { - case RleSkippedPixelHandling.FirstColorOfPalette: - color.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); - break; - case RleSkippedPixelHandling.Transparent: - color.FromScaledVector4(Vector4.Zero); - break; - - // Default handling for skipped pixels is black (which is what System.Drawing is also doing). - default: - color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - break; - } - } - else + pixelRow[x] = this.rleSkippedPixelHandling switch { - color.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); - } + RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])), + RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero), - pixelRow[x] = color; + // Default handling for skipped pixels is black (which is what System.Drawing is also doing). + _ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)), + }; } - } - else - { - // Fast path without any undefined pixels. - for (int x = 0; x < width; x++) + else { - color.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref colors[colorIdx * 4])); } } } + else + { + // Fast path without any undefined pixels. + for (int x = 0; x < width; x++) + { + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref colors[bufferRow[x] * 4])); + } + } } } @@ -375,66 +363,54 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals private void ReadRle24(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted) where TPixel : unmanaged, IPixel { - TPixel color = default; - using (IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * 3, AllocationOptions.Clean)) - using (IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean)) - using (IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean)) - { - Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; - Span undefinedPixelsSpan = undefinedPixels.Memory.Span; - Span bufferSpan = buffer.GetSpan(); + using IMemoryOwner buffer = this.memoryAllocator.Allocate(width * height * 3, AllocationOptions.Clean); + using IMemoryOwner undefinedPixels = this.memoryAllocator.Allocate(width * height, AllocationOptions.Clean); + using IMemoryOwner rowsWithUndefinedPixels = this.memoryAllocator.Allocate(height, AllocationOptions.Clean); + Span rowsWithUndefinedPixelsSpan = rowsWithUndefinedPixels.Memory.Span; + Span undefinedPixelsSpan = undefinedPixels.Memory.Span; + Span bufferSpan = buffer.GetSpan(); - this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); - for (int y = 0; y < height; y++) + this.UncompressRle24(stream, width, bufferSpan, undefinedPixelsSpan, rowsWithUndefinedPixelsSpan); + for (int y = 0; y < height; y++) + { + int newY = Invert(y, height, inverted); + Span pixelRow = pixels.DangerousGetRowSpan(newY); + bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; + if (rowHasUndefinedPixels) { - int newY = Invert(y, height, inverted); - Span pixelRow = pixels.DangerousGetRowSpan(newY); - bool rowHasUndefinedPixels = rowsWithUndefinedPixelsSpan[y]; - if (rowHasUndefinedPixels) + // Slow path with undefined pixels. + int yMulWidth = y * width; + int rowStartIdx = yMulWidth * 3; + for (int x = 0; x < width; x++) { - // Slow path with undefined pixels. - int yMulWidth = y * width; - int rowStartIdx = yMulWidth * 3; - for (int x = 0; x < width; x++) + int idx = rowStartIdx + (x * 3); + if (undefinedPixelsSpan[yMulWidth + x]) { - int idx = rowStartIdx + (x * 3); - if (undefinedPixelsSpan[yMulWidth + x]) - { - switch (this.rleSkippedPixelHandling) - { - case RleSkippedPixelHandling.FirstColorOfPalette: - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - break; - case RleSkippedPixelHandling.Transparent: - color.FromScaledVector4(Vector4.Zero); - break; - - // Default handling for skipped pixels is black (which is what System.Drawing is also doing). - default: - color.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)); - break; - } - } - else + pixelRow[x] = this.rleSkippedPixelHandling switch { - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - } + RleSkippedPixelHandling.FirstColorOfPalette => TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])), + RleSkippedPixelHandling.Transparent => TPixel.FromScaledVector4(Vector4.Zero), - pixelRow[x] = color; + // Default handling for skipped pixels is black (which is what System.Drawing is also doing). + _ => TPixel.FromScaledVector4(new Vector4(0.0f, 0.0f, 0.0f, 1.0f)), + }; } - } - else - { - // Fast path without any undefined pixels. - int rowStartIdx = y * width * 3; - for (int x = 0; x < width; x++) + else { - int idx = rowStartIdx + (x * 3); - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); } } } + else + { + // Fast path without any undefined pixels. + int rowStartIdx = y * width * 3; + for (int x = 0; x < width; x++) + { + int idx = rowStartIdx + (x * 3); + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); + } + } } } @@ -492,7 +468,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals int max = cmd[1]; int bytesToRead = (int)(((uint)max + 1) / 2); - Span run = bytesToRead <= 128 ? scratchBuffer.Slice(0, bytesToRead) : new byte[bytesToRead]; + Span run = bytesToRead <= 128 ? scratchBuffer[..bytesToRead] : new byte[bytesToRead]; stream.Read(run); @@ -598,7 +574,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals // Take this number of bytes from the stream as uncompressed data. int length = cmd[1]; - Span run = length <= 128 ? scratchBuffer.Slice(0, length) : new byte[length]; + Span run = length <= 128 ? scratchBuffer[..length] : new byte[length]; stream.Read(run); @@ -680,7 +656,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals int length = cmd[1]; int length3 = length * 3; - Span run = length3 <= 128 ? scratchBuffer.Slice(0, length3) : new byte[length3]; + Span run = length3 <= 128 ? scratchBuffer[..length3] : new byte[length3]; stream.Read(run); @@ -835,7 +811,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals } using IMemoryOwner row = this.memoryAllocator.Allocate(arrayWidth + padding, AllocationOptions.Clean); - TPixel color = default; Span rowSpan = row.GetSpan(); for (int y = 0; y < height; y++) @@ -856,8 +831,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals { int colorIndex = ((rowSpan[offset] >> (8 - bitsPerPixel - (shift * bitsPerPixel))) & mask) * bytesPerColorMapEntry; - color.FromBgr24(Unsafe.As(ref colors[colorIndex])); - pixelRow[newX] = color; + pixelRow[newX] = TPixel.FromBgr24(Unsafe.As(ref colors[colorIndex])); } offset++; @@ -882,8 +856,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals { int padding = CalculatePadding(width, 2); int stride = (width * 2) + padding; - TPixel color = default; - int rightShiftRedMask = CalculateRightShift((uint)redMask); int rightShiftGreenMask = CalculateRightShift((uint)greenMask); int rightShiftBlueMask = CalculateRightShift((uint)blueMask); @@ -917,8 +889,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals int b = (blueMaskBits == 5) ? GetBytesFrom5BitValue((temp & blueMask) >> rightShiftBlueMask) : GetBytesFrom6BitValue((temp & blueMask) >> rightShiftBlueMask); Rgb24 rgb = new((byte)r, (byte)g, (byte)b); - color.FromRgb24(rgb); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgb24(rgb); offset += 2; } } @@ -1107,8 +1078,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals { Bgra32 bgra = bgraRowSpan[x]; bgra.A = byte.MaxValue; - ref TPixel pixel = ref pixelSpan[x]; - pixel.FromBgra32(bgra); + pixelSpan[x] = TPixel.FromBgra32(bgra); } } } @@ -1129,7 +1099,6 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals private void ReadRgb32BitFields(BufferedReadStream stream, Buffer2D pixels, int width, int height, bool inverted, int redMask, int greenMask, int blueMask, int alphaMask) where TPixel : unmanaged, IPixel { - TPixel color = default; int padding = CalculatePadding(width, 4); int stride = (width * 4) + padding; @@ -1179,18 +1148,17 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals g * invMaxValueGreen, b * invMaxValueBlue, alpha); - color.FromScaledVector4(vector4); + pixelRow[x] = TPixel.FromScaledVector4(vector4); } else { byte r = (byte)((temp & redMask) >> rightShiftRedMask); byte g = (byte)((temp & greenMask) >> rightShiftGreenMask); byte b = (byte)((temp & blueMask) >> rightShiftBlueMask); - byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : (byte)255; - color.FromRgba32(new Rgba32(r, g, b, a)); + byte a = alphaMask != 0 ? (byte)((temp & alphaMask) >> rightShiftAlphaMask) : byte.MaxValue; + pixelRow[x] = TPixel.FromRgba32(new(r, g, b, a)); } - pixelRow[x] = color; offset += 4; } } @@ -1468,7 +1436,7 @@ internal sealed class BmpDecoderCore : IImageDecoderInternals colorMapSizeBytes = this.infoHeader.ClrUsed * bytesPerColorMapEntry; } - palette = Array.Empty(); + palette = []; if (colorMapSizeBytes > 0) { diff --git a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs index 8916da6e0e..d64792eba7 100644 --- a/src/ImageSharp/Formats/Gif/GifDecoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifDecoderCore.cs @@ -185,7 +185,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals { uint frameCount = 0; ImageFrameMetadata? previousFrame = null; - List framesMetadata = new(); + List framesMetadata = []; try { this.ReadLogicalScreenDescriptorAndGlobalColorTable(stream); @@ -595,9 +595,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals for (int x = descriptorLeft; x < descriptorRight && x < imageWidth; x++) { int index = Numerics.Clamp(Unsafe.Add(ref indicesRowRef, (uint)(x - descriptorLeft)), 0, colorTableMaxIdx); - ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x); - Rgb24 rgb = colorTable[index]; - pixel.FromRgb24(rgb); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); } } else @@ -613,9 +611,7 @@ internal sealed class GifDecoderCore : IImageDecoderInternals } int index = Numerics.Clamp(rawIndex, 0, colorTableMaxIdx); - ref TPixel pixel = ref Unsafe.Add(ref rowRef, (uint)x); - Rgb24 rgb = colorTable[index]; - pixel.FromRgb24(rgb); + Unsafe.Add(ref rowRef, (uint)x) = TPixel.FromRgb24(colorTable[index]); } } } diff --git a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs index 1215768e4b..95429e6065 100644 --- a/src/ImageSharp/Formats/Gif/GifEncoderCore.cs +++ b/src/ImageSharp/Formats/Gif/GifEncoderCore.cs @@ -169,7 +169,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals this.EncodeFirstFrame(stream, frameMetadata, quantized); // Capture the global palette for reuse on subsequent frames and cleanup the quantized frame. - TPixel[] globalPalette = image.Frames.Count == 1 ? Array.Empty() : quantized.Palette.ToArray(); + TPixel[] globalPalette = image.Frames.Count == 1 ? [] : quantized.Palette.ToArray(); this.EncodeAdditionalFrames(stream, image, globalPalette, derivedTransparencyIndex, frameMetadata.DisposalMethod); @@ -488,8 +488,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals int index = -1; if (quantized != null) { - TPixel transparentPixel = default; - transparentPixel.FromScaledVector4(Vector4.Zero); + TPixel transparentPixel = TPixel.FromScaledVector4(Vector4.Zero); ReadOnlySpan palette = quantized.Palette.Span; // Transparent pixels are much more likely to be found at the end of a palette. @@ -693,7 +692,7 @@ internal sealed class GifEncoderCore : IImageEncoderInternals } IMemoryOwner? owner = null; - Span extensionBuffer = stackalloc byte[0]; // workaround compiler limitation + scoped Span extensionBuffer = []; // workaround compiler limitation if (extensionSize > 128) { owner = this.memoryAllocator.Allocate(extensionSize + 3); diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index aa3603cfbb..993f53269d 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -328,18 +328,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable => clone.ProcessPixelRows(accessor => { // TODO: We should be able to speed this up with SIMD and masking. - Rgba32 rgba32 = default; Rgba32 transparent = Color.Transparent.ToPixel(); for (int y = 0; y < accessor.Height; y++) { Span span = accessor.GetRowSpan(y); for (int x = 0; x < accessor.Width; x++) { - span[x].ToRgba32(ref rgba32); - - if (rgba32.A is 0) + ref TPixel pixel = ref span[x]; + Rgba32 rgba = pixel.ToRgba32(); + if (rgba.A is 0) { - span[x].FromRgba32(transparent); + pixel = TPixel.FromRgba32(transparent); } } } diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index 39b3fff27a..aa937a8e2a 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -42,7 +42,6 @@ internal static class PngScanlineProcessor where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); int scaleFactor = 255 / (ColorNumerics.GetColorCountForBitDepth(bitDepth) - 1); @@ -55,8 +54,7 @@ internal static class PngScanlineProcessor for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - pixel.FromL16(Unsafe.As(ref luminance)); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL16(Unsafe.As(ref luminance)); } } else @@ -64,8 +62,7 @@ internal static class PngScanlineProcessor for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - pixel.FromL8(Unsafe.As(ref luminance)); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromL8(Unsafe.As(ref luminance)); } } @@ -75,30 +72,22 @@ internal static class PngScanlineProcessor if (bitDepth == 16) { L16 transparent = transparentColor.Value.ToPixel(); - La32 source = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += 2) { ushort luminance = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - source.L = luminance; - source.A = luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromLa32(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + La32 source = new(luminance, luminance.Equals(transparent.PackedValue) ? ushort.MinValue : ushort.MaxValue); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa32(source); } } else { byte transparent = (byte)(transparentColor.Value.ToPixel().PackedValue * scaleFactor); - La16 source = default; for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { byte luminance = (byte)(Unsafe.Add(ref scanlineSpanRef, o) * scaleFactor); - source.L = luminance; - source.A = luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue; - - pixel.FromLa16(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + La16 source = new(luminance, luminance.Equals(transparent) ? byte.MinValue : byte.MaxValue); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(source); } } } @@ -133,34 +122,28 @@ internal static class PngScanlineProcessor where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (bitDepth == 16) { - La32 source = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += 4) { - source.L = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); - source.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); + ushort l = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, 2)); + ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + 2, 2)); - pixel.FromLa32(source); - Unsafe.Add(ref rowSpanRef, (uint)x) = pixel; + Unsafe.Add(ref rowSpanRef, (uint)x) = TPixel.FromLa32(new(l, a)); } } else { - La16 source = default; nuint offset2 = 0; for (nuint x = offset; x < frameControl.XMax; x += increment) { - source.L = Unsafe.Add(ref scanlineSpanRef, offset2); - source.A = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample); - - pixel.FromLa16(source); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte l = Unsafe.Add(ref scanlineSpanRef, offset2); + byte a = Unsafe.Add(ref scanlineSpanRef, offset2 + bytesPerSample); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromLa16(new(l, a)); offset2 += bytesPerPixel; } } @@ -194,7 +177,6 @@ internal static class PngScanlineProcessor PngThrowHelper.ThrowMissingPalette(); } - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); @@ -202,8 +184,7 @@ internal static class PngScanlineProcessor for (nuint x = pixelOffset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); - pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel()); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel()); } } @@ -243,8 +224,6 @@ internal static class PngScanlineProcessor where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - - TPixel pixel = default; ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); @@ -252,16 +231,13 @@ internal static class PngScanlineProcessor { if (bitDepth == 16) { - Rgb48 rgb48 = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - pixel.FromRgb48(rgb48); - Unsafe.Add(ref rowSpanRef, x) = pixel; + ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb48(new(r, g, b)); } } else if (pixelOffset == 0 && increment == 1) @@ -274,16 +250,13 @@ internal static class PngScanlineProcessor } else { - Rgb24 rgb = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgb.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgb.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - - pixel.FromRgb24(rgb); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o); + byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgb24(new(r, g, b)); } } @@ -293,27 +266,20 @@ internal static class PngScanlineProcessor if (bitDepth == 16) { Rgb48 transparent = transparentColor.Value.ToPixel(); - - Rgb48 rgb48 = default; - Rgba64 rgba64 = default; + Rgba64 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgb48.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgb48.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgb48.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - - rgba64.Rgb = rgb48; - rgba64.A = rgb48.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; + rgba.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + rgba.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + rgba.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + rgba.A = rgba.Rgb.Equals(transparent) ? ushort.MinValue : ushort.MaxValue; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(rgba); } } else { Rgb24 transparent = transparentColor.Value.ToPixel(); - Rgba32 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) @@ -322,9 +288,7 @@ internal static class PngScanlineProcessor rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); rgba.A = transparent.Equals(rgba.Rgb) ? byte.MinValue : byte.MaxValue; - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(rgba); } } } @@ -362,22 +326,18 @@ internal static class PngScanlineProcessor where TPixel : unmanaged, IPixel { uint offset = pixelOffset + frameControl.XOffset; - TPixel pixel = default; ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); if (bitDepth == 16) { - Rgba64 rgba64 = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgba64.R = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); - rgba64.G = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); - rgba64.B = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); - rgba64.A = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); - - pixel.FromRgba64(rgba64); - Unsafe.Add(ref rowSpanRef, x) = pixel; + ushort r = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o, bytesPerSample)); + ushort g = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + bytesPerSample, bytesPerSample)); + ushort b = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (2 * bytesPerSample), bytesPerSample)); + ushort a = BinaryPrimitives.ReadUInt16BigEndian(scanlineSpan.Slice(o + (3 * bytesPerSample), bytesPerSample)); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba64(new(r, g, b, a)); } } else if (pixelOffset == 0 && increment == 1) @@ -391,17 +351,14 @@ internal static class PngScanlineProcessor else { ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); - Rgba32 rgba = default; int o = 0; for (nuint x = offset; x < frameControl.XMax; x += increment, o += bytesPerPixel) { - rgba.R = Unsafe.Add(ref scanlineSpanRef, (uint)o); - rgba.G = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); - rgba.B = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); - rgba.A = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample))); - - pixel.FromRgba32(rgba); - Unsafe.Add(ref rowSpanRef, x) = pixel; + byte r = Unsafe.Add(ref scanlineSpanRef, (uint)o); + byte g = Unsafe.Add(ref scanlineSpanRef, (uint)(o + bytesPerSample)); + byte b = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (2 * bytesPerSample))); + byte a = Unsafe.Add(ref scanlineSpanRef, (uint)(o + (3 * bytesPerSample))); + Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs b/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs index deb0a37f05..86d81d8345 100644 --- a/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs +++ b/src/ImageSharp/Formats/Qoi/QoiDecoderCore.cs @@ -149,7 +149,7 @@ internal class QoiDecoderCore : IImageDecoderInternals Span previouslySeenPixels = previouslySeenPixelsBuffer.GetSpan(); Rgba32 previousPixel = new(0, 0, 0, 255); - // We save the pixel to avoid loosing the fully opaque black pixel + // We save the pixel to avoid losing the fully opaque black pixel // See https://github.com/phoboslab/qoi/issues/258 int pixelArrayPosition = GetArrayPosition(previousPixel); previouslySeenPixels[pixelArrayPosition] = previousPixel; @@ -174,7 +174,7 @@ internal class QoiDecoderCore : IImageDecoderInternals } readPixel.A = previousPixel.A; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -186,7 +186,7 @@ internal class QoiDecoderCore : IImageDecoderInternals ThrowInvalidImageContentException(); } - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -197,7 +197,7 @@ internal class QoiDecoderCore : IImageDecoderInternals // Getting one pixel from previously seen pixels case QoiChunk.QoiOpIndex: readPixel = previouslySeenPixels[operationByte]; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); break; // Get one pixel from the difference (-2..1) of the previous pixel @@ -211,7 +211,7 @@ internal class QoiDecoderCore : IImageDecoderInternals G = (byte)Numerics.Modulo256(previousPixel.G + (greenDifference - 2)), B = (byte)Numerics.Modulo256(previousPixel.B + (blueDifference - 2)) }; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -227,7 +227,7 @@ internal class QoiDecoderCore : IImageDecoderInternals int currentRed = Numerics.Modulo256(diffRedDG - 8 + (diffGreen - 32) + previousPixel.R); int currentBlue = Numerics.Modulo256(diffBlueDG - 8 + (diffGreen - 32) + previousPixel.B); readPixel = previousPixel with { R = (byte)currentRed, B = (byte)currentBlue, G = (byte)currentGreen }; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); pixelArrayPosition = GetArrayPosition(readPixel); previouslySeenPixels[pixelArrayPosition] = readPixel; break; @@ -241,7 +241,7 @@ internal class QoiDecoderCore : IImageDecoderInternals } readPixel = previousPixel; - pixel.FromRgba32(readPixel); + pixel = TPixel.FromRgba32(readPixel); for (int k = -1; k < repetitions; k++, j++) { if (j == row.Length) diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 26e057bff9..de99c475be 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -222,7 +222,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals private void ReadPaletted(BufferedReadStream stream, int width, int height, Buffer2D pixels, Span palette, int colorMapPixelSizeInBytes, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); for (int y = 0; y < height; y++) @@ -237,14 +236,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals { for (int x = width - 1; x >= 0; x--) { - this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + this.ReadPalettedBgra16Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -255,14 +254,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals { for (int x = width - 1; x >= 0; x--) { - ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgr24Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -273,14 +272,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals { for (int x = width - 1; x >= 0; x--) { - ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } else { for (int x = 0; x < width; x++) { - ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, color, pixelRow); + ReadPalettedBgra32Pixel(stream, palette, colorMapPixelSizeInBytes, x, pixelRow); } } @@ -319,16 +318,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals switch (colorMapPixelSizeInBytes) { case 1: - color.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromL8(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 2: - this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes, ref color); + color = this.ReadPalettedBgra16Pixel(palette, bufferSpan[idx], colorMapPixelSizeInBytes); break; case 3: - color.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromBgr24(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; case 4: - color.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); + color = TPixel.FromBgra32(Unsafe.As(ref palette[bufferSpan[idx] * colorMapPixelSizeInBytes])); break; } @@ -350,17 +349,15 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals private void ReadMonoChrome(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - bool invertX = InvertX(origin); - if (invertX) + if (InvertX(origin)) { - TPixel color = default; for (int y = 0; y < height; y++) { int newY = InvertY(y, height, origin); Span pixelSpan = pixels.DangerousGetRowSpan(newY); for (int x = width - 1; x >= 0; x--) { - ReadL8Pixel(stream, color, x, pixelSpan); + ReadL8Pixel(stream, x, pixelSpan); } } @@ -369,8 +366,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 1, 0); Span rowSpan = row.GetSpan(); - bool invertY = InvertY(origin); - if (invertY) + if (InvertY(origin)) { for (int y = height - 1; y >= 0; y--) { @@ -398,7 +394,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals private void ReadBgra16(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 2, 0); Span rowSpan = row.GetSpan(); @@ -426,14 +421,12 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals if (this.fileHeader.ImageType == TgaImageType.BlackAndWhite) { - color.FromLa16(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); + pixelSpan[x] = TPixel.FromLa16(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } else { - color.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); + pixelSpan[x] = TPixel.FromBgra5551(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } - - pixelSpan[x] = color; } } else @@ -477,18 +470,16 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals private void ReadBgr24(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - bool invertX = InvertX(origin); - if (invertX) + if (InvertX(origin)) { Span scratchBuffer = stackalloc byte[4]; - TPixel color = default; for (int y = 0; y < height; y++) { int newY = InvertY(y, height, origin); Span pixelSpan = pixels.DangerousGetRowSpan(newY); for (int x = width - 1; x >= 0; x--) { - ReadBgr24Pixel(stream, color, x, pixelSpan, scratchBuffer); + ReadBgr24Pixel(stream, x, pixelSpan, scratchBuffer); } } @@ -497,9 +488,8 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals using IMemoryOwner row = this.memoryAllocator.AllocatePaddedPixelRowBuffer(width, 3, 0); Span rowSpan = row.GetSpan(); - bool invertY = InvertY(origin); - if (invertY) + if (InvertY(origin)) { for (int y = height - 1; y >= 0; y--) { @@ -527,7 +517,6 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals private void ReadBgra32(BufferedReadStream stream, int width, int height, Buffer2D pixels, TgaImageOrigin origin) where TPixel : unmanaged, IPixel { - TPixel color = default; bool invertX = InvertX(origin); Guard.NotNull(this.tgaMetadata); @@ -565,14 +554,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals { for (int x = width - 1; x >= 0; x--) { - this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer); + this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer); } } else { for (int x = 0; x < width; x++) { - this.ReadBgra32Pixel(stream, x, color, pixelRow, scratchBuffer); + this.ReadBgra32Pixel(stream, x, pixelRow, scratchBuffer); } } } @@ -610,7 +599,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals switch (bytesPerPixel) { case 1: - color.FromL8(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromL8(Unsafe.As(ref bufferSpan[idx])); break; case 2: if (!this.hasAlpha) @@ -621,26 +610,26 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals if (this.fileHeader.ImageType == TgaImageType.RleBlackAndWhite) { - color.FromLa16(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromLa16(Unsafe.As(ref bufferSpan[idx])); } else { - color.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgra5551(Unsafe.As(ref bufferSpan[idx])); } break; case 3: - color.FromBgr24(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgr24(Unsafe.As(ref bufferSpan[idx])); break; case 4: if (this.hasAlpha) { - color.FromBgra32(Unsafe.As(ref bufferSpan[idx])); + color = TPixel.FromBgra32(Unsafe.As(ref bufferSpan[idx])); } else { byte alpha = alphaBits == 0 ? byte.MaxValue : bufferSpan[idx + 3]; - color.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha)); + color = TPixel.FromBgra32(new Bgra32(bufferSpan[idx + 2], bufferSpan[idx + 1], bufferSpan[idx], alpha)); } break; @@ -677,16 +666,15 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadL8Pixel(BufferedReadStream stream, TPixel color, int x, Span pixelSpan) + private static void ReadL8Pixel(BufferedReadStream stream, int x, Span pixelSpan) where TPixel : unmanaged, IPixel { byte pixelValue = (byte)stream.ReadByte(); - color.FromL8(Unsafe.As(ref pixelValue)); - pixelSpan[x] = color; + pixelSpan[x] = TPixel.FromL8(Unsafe.As(ref pixelValue)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadBgr24Pixel(BufferedReadStream stream, TPixel color, int x, Span pixelSpan, Span scratchBuffer) + private static void ReadBgr24Pixel(BufferedReadStream stream, int x, Span pixelSpan, Span scratchBuffer) where TPixel : unmanaged, IPixel { int bytesRead = stream.Read(scratchBuffer, 0, 3); @@ -695,8 +683,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read a bgr pixel"); } - color.FromBgr24(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); - pixelSpan[x] = color; + pixelSpan[x] = TPixel.FromBgr24(Unsafe.As(ref MemoryMarshal.GetReference(scratchBuffer))); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -714,7 +701,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadBgra32Pixel(BufferedReadStream stream, int x, TPixel color, Span pixelRow, Span scratchBuffer) + private void ReadBgra32Pixel(BufferedReadStream stream, int x, Span pixelRow, Span scratchBuffer) where TPixel : unmanaged, IPixel { int bytesRead = stream.Read(scratchBuffer, 0, 4); @@ -726,8 +713,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals Guard.NotNull(this.tgaMetadata); byte alpha = this.tgaMetadata.AlphaChannelBits == 0 ? byte.MaxValue : scratchBuffer[3]; - color.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgra32(new Bgra32(scratchBuffer[2], scratchBuffer[1], scratchBuffer[0], alpha)); } [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -745,7 +731,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private void ReadPalettedBgra16Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -754,16 +740,14 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index"); } - this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes, ref color); - pixelRow[x] = color; + pixelRow[x] = this.ReadPalettedBgra16Pixel(palette, colorIndex, colorMapPixelSizeInBytes); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private void ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes, ref TPixel color) + private TPixel ReadPalettedBgra16Pixel(Span palette, int index, int colorMapPixelSizeInBytes) where TPixel : unmanaged, IPixel { - Bgra5551 bgra = default; - bgra.FromBgra5551(Unsafe.As(ref palette[index * colorMapPixelSizeInBytes])); + Bgra5551 bgra = Unsafe.As(ref palette[index * colorMapPixelSizeInBytes]); if (!this.hasAlpha) { @@ -771,11 +755,11 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals bgra.PackedValue = (ushort)(bgra.PackedValue | 0x8000); } - color.FromBgra5551(bgra); + return TPixel.FromBgra5551(bgra); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadPalettedBgr24Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private static void ReadPalettedBgr24Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -784,12 +768,11 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index"); } - color.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgr24(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static void ReadPalettedBgra32Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, TPixel color, Span pixelRow) + private static void ReadPalettedBgra32Pixel(BufferedReadStream stream, Span palette, int colorMapPixelSizeInBytes, int x, Span pixelRow) where TPixel : unmanaged, IPixel { int colorIndex = stream.ReadByte(); @@ -798,8 +781,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals TgaThrowHelper.ThrowInvalidImageContentException("Not enough data to read color index"); } - color.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromBgra32(Unsafe.As(ref palette[colorIndex * colorMapPixelSizeInBytes])); } /// diff --git a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs index bbb476c017..bb13798c50 100644 --- a/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaEncoderCore.cs @@ -5,7 +5,6 @@ using System.Buffers; using System.Buffers.Binary; using System.Numerics; using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; @@ -160,7 +159,6 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals private void WriteRunLengthEncodedImage(Stream stream, ImageFrame image) where TPixel : unmanaged, IPixel { - Rgba32 color = default; Buffer2D pixels = image.PixelBuffer; for (int y = 0; y < image.Height; y++) { @@ -168,14 +166,13 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals for (int x = 0; x < image.Width;) { TPixel currentPixel = pixelRow[x]; - currentPixel.ToRgba32(ref color); byte equalPixelCount = FindEqualPixels(pixelRow, x); if (equalPixelCount > 0) { // Write the number of equal pixels, with the high bit set, indicating ist a compressed pixel run. stream.WriteByte((byte)(equalPixelCount | 128)); - this.WritePixel(stream, currentPixel, color); + this.WritePixel(stream, currentPixel, currentPixel.ToRgba32()); x += equalPixelCount + 1; } else @@ -183,13 +180,12 @@ internal sealed class TgaEncoderCore : IImageEncoderInternals // Write Raw Packet (i.e., Non-Run-Length Encoded): byte unEqualPixelCount = FindUnEqualPixels(pixelRow, x); stream.WriteByte(unEqualPixelCount); - this.WritePixel(stream, currentPixel, color); + this.WritePixel(stream, currentPixel, currentPixel.ToRgba32()); x++; for (int i = 0; i < unEqualPixelCount; i++) { currentPixel = pixelRow[x]; - currentPixel.ToRgba32(ref color); - this.WritePixel(stream, currentPixel, color); + this.WritePixel(stream, currentPixel, currentPixel.ToRgba32()); x++; } } diff --git a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs index 1c838b0b76..30a9335286 100644 --- a/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs +++ b/src/ImageSharp/Formats/Tiff/Compression/HorizontalPredictor.cs @@ -102,8 +102,7 @@ internal static class HorizontalPredictor byte r = (byte)(rowRgb[x].R - rowRgb[x - 1].R); byte g = (byte)(rowRgb[x].G - rowRgb[x - 1].G); byte b = (byte)(rowRgb[x].B - rowRgb[x - 1].B); - var rgb = new Rgb24(r, g, b); - rowRgb[x].FromRgb24(rgb); + rowRgb[x] = new Rgb24(r, g, b); } } } @@ -128,8 +127,7 @@ internal static class HorizontalPredictor for (int x = rowL16.Length - 1; x >= 1; x--) { - ushort val = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue); - rowL16[x].PackedValue = val; + rowL16[x].PackedValue = (ushort)(rowL16[x].PackedValue - rowL16[x - 1].PackedValue); } } } @@ -181,13 +179,13 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort pixelValue = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort diff = TiffUtilities.ConvertToUShortBigEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, pixelValue); offset += 2; @@ -200,13 +198,13 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort pixelValue = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort pixelValue = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort diff = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort diff = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, pixelValue); offset += 2; @@ -225,13 +223,13 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint pixelValue = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint diff = TiffUtilities.ConvertToUIntBigEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, pixelValue); offset += 4; @@ -244,13 +242,13 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint pixelValue = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint pixelValue = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint diff = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint diff = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); pixelValue += diff; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, pixelValue); offset += 4; @@ -278,8 +276,7 @@ internal static class HorizontalPredictor r += pixel.R; g += pixel.G; b += pixel.B; - var rgb = new Rgb24(r, g, b); - pixel.FromRgb24(rgb); + pixel = new Rgb24(r, g, b); } } } @@ -305,8 +302,7 @@ internal static class HorizontalPredictor g += pixel.G; b += pixel.B; a += pixel.A; - var rgb = new Rgba32(r, g, b, a); - pixel.FromRgba32(rgb); + pixel = new Rgba32(r, g, b, a); } } } @@ -321,29 +317,29 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); offset += 2; @@ -356,29 +352,29 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); offset += 2; @@ -397,37 +393,37 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort a = TiffUtils.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortBigEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, b); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtils.ConvertToUShortBigEndian(rowSpan); + ushort deltaA = TiffUtilities.ConvertToUShortBigEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt16BigEndian(rowSpan, a); offset += 2; @@ -440,37 +436,37 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - ushort r = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort g = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort b = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; - ushort a = TiffUtils.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortLittleEndian(rowBytes.Slice(offset, 2)); offset += 2; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 2); - ushort deltaR = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaR = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, r); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaG = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaG = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, g); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaB = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaB = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, b); offset += 2; rowSpan = rowBytes.Slice(offset, 2); - ushort deltaA = TiffUtils.ConvertToUShortLittleEndian(rowSpan); + ushort deltaA = TiffUtilities.ConvertToUShortLittleEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt16LittleEndian(rowSpan, a); offset += 2; @@ -489,29 +485,29 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); offset += 4; @@ -524,29 +520,29 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); offset += 4; @@ -565,37 +561,37 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint a = TiffUtils.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntBigEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntBigEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntBigEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntBigEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, b); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtils.ConvertToUIntBigEndian(rowSpan); + uint deltaA = TiffUtilities.ConvertToUIntBigEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt32BigEndian(rowSpan, a); offset += 4; @@ -608,37 +604,37 @@ internal static class HorizontalPredictor { int offset = 0; Span rowBytes = pixelBytes.Slice(y * rowBytesCount, rowBytesCount); - uint r = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint g = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint b = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; - uint a = TiffUtils.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(rowBytes.Slice(offset, 4)); offset += 4; for (int x = 1; x < width; x++) { Span rowSpan = rowBytes.Slice(offset, 4); - uint deltaR = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaR = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); r += deltaR; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, r); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaG = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaG = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); g += deltaG; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, g); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaB = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaB = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); b += deltaB; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, b); offset += 4; rowSpan = rowBytes.Slice(offset, 4); - uint deltaA = TiffUtils.ConvertToUIntLittleEndian(rowSpan); + uint deltaA = TiffUtilities.ConvertToUIntLittleEndian(rowSpan); a += deltaA; BinaryPrimitives.WriteUInt32LittleEndian(rowSpan, a); offset += 4; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs index 8763f99570..2ef261811b 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero16TiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 16-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero16TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +33,8 @@ internal class BlackIsZero16TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - L16 l16 = TiffUtils.L16Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); + L16 l16 = TiffUtilities.L16Default; + TPixel color = TPixel.FromScaledVector4(Vector4.Zero); int offset = 0; for (int y = top; y < top + height; y++) @@ -44,10 +44,10 @@ internal class BlackIsZero16TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort intensity = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs index 89d1b9d20e..c9c0ee5810 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero1TiffColor{TPixel}.cs @@ -19,11 +19,9 @@ internal class BlackIsZero1TiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { nuint offset = 0; - TPixel colorBlack = default; - TPixel colorWhite = default; + TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel()); + TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel()); - colorBlack.FromRgba32(Color.Black.ToPixel()); - colorWhite.FromRgba32(Color.White.ToPixel()); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs index d57130a5f5..07bf3d1bd7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero24TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 24-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero24TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class BlackIsZero24TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -40,10 +38,10 @@ internal class BlackIsZero24TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = TiffUtils.ConvertToUIntBigEndian(buffer); + uint intensity = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } else @@ -51,10 +49,10 @@ internal class BlackIsZero24TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint intensity = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs index df37327c35..ac316459d8 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero32FloatTiffColor{TPixel}.cs @@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation for 32-bit float grayscale images. /// +/// The type of pixel format. internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +25,6 @@ internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int offset = 0; @@ -41,9 +40,7 @@ internal class BlackIsZero32FloatTiffColor : TiffBaseColorDecoder : TiffBaseColorDecoder /// Implements the 'BlackIsZero' photometric interpretation for 32-bit grayscale images. /// +/// The type of pixel format. internal class BlackIsZero32TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,9 +25,6 @@ internal class BlackIsZero32TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) { @@ -36,20 +33,20 @@ internal class BlackIsZero32TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint intensity = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint intensity = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs index 16b995441c..1d33f1a248 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZero4TiffColor{TPixel}.cs @@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation (optimized for 4-bit grayscale images). /// +/// The type of pixel format. internal class BlackIsZero4TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; bool isOddWidth = (width & 1) == 1; - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRowSpan = pixels.DangerousGetRowSpan(y); for (int x = left; x < left + width - 1;) { byte byteData = data[offset++]; - - byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[x++] = color; - - byte intensity2 = (byte)((byteData & 0x0F) * 17); - l8.PackedValue = intensity2; - color.FromL8(l8); - - pixelRowSpan[x++] = color; + pixelRowSpan[x++] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17))); + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((byteData & 0x0F) * 17))); } if (isOddWidth) { byte byteData = data[offset++]; - - byte intensity1 = (byte)(((byteData & 0xF0) >> 4) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[left + width - 1] = color; + pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)(((byteData & 0xF0) >> 4) * 17))); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs index b086cb43ee..709c2bf649 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/BlackIsZeroTiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,25 +10,23 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'BlackIsZero' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class BlackIsZeroTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly ushort bitsPerSample0; - private readonly float factor; public BlackIsZeroTiffColor(TiffBitsPerSample bitsPerSample) { this.bitsPerSample0 = bitsPerSample.Channel0; - this.factor = (1 << this.bitsPerSample0) - 1.0f; + this.factor = (1 << this.bitsPerSample0) - 1f; } /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -38,9 +35,7 @@ internal class BlackIsZeroTiffColor : TiffBaseColorDecoder { int value = bitReader.ReadBits(this.bitsPerSample0); float intensity = value / this.factor; - - color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(intensity, intensity, intensity, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs index eb2fe353e6..6be584581f 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CieLabPlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.Memory; @@ -13,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'CieLab' with the planar configuration. /// +/// The type of pixel format. internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -23,11 +23,10 @@ internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Span l = data[0].GetSpan(); - Span a = data[1].GetSpan(); Span b = data[2].GetSpan(); + Span a = data[1].GetSpan(); + Span l = data[0].GetSpan(); - TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { @@ -36,9 +35,7 @@ internal class CieLabPlanarTiffColor : TiffBasePlanarColorDecoder /// Implements decoding pixel data with photometric interpretation of type 'CieLab'. /// +/// The type of pixel format. internal class CieLabTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private static readonly ColorSpaceConverter ColorSpaceConverter = new(); - - private const float Inv255 = 1.0f / 255.0f; + private const float Inv255 = 1f / 255f; /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { @@ -33,9 +31,7 @@ internal class CieLabTiffColor : TiffBaseColorDecoder float l = (data[offset] & 0xFF) * 100f * Inv255; CieLab lab = new(l, (sbyte)data[offset + 1], (sbyte)data[offset + 2]); Rgb rgb = ColorSpaceConverter.ToRgb(lab); - - color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1f)); offset += 3; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs index 2074fb2544..77baa5351a 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/CmykTiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.ColorSpaces; using SixLabors.ImageSharp.ColorSpaces.Conversion; using SixLabors.ImageSharp.Memory; @@ -12,12 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; internal class CmykTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { - private const float Inv255 = 1 / 255.0f; + private const float Inv255 = 1f / 255f; /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - TPixel color = default; int offset = 0; for (int y = top; y < top + height; y++) { @@ -26,9 +24,7 @@ internal class CmykTiffColor : TiffBaseColorDecoder { Cmyk cmyk = new(data[offset] * Inv255, data[offset + 1] * Inv255, data[offset + 2] * Inv255, data[offset + 3] * Inv255); Rgb rgb = ColorSpaceConverter.ToRgb(in cmyk); - - color.FromScaledVector4(new Vector4(rgb.R, rgb.G, rgb.B, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(rgb.R, rgb.G, rgb.B, 1.0f)); offset += 4; } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs index 22db1918cb..745e5846a9 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/PaletteTiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'PaletteTiffColor' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class PaletteTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -18,8 +18,11 @@ internal class PaletteTiffColor : TiffBaseColorDecoder private readonly TPixel[] palette; - private const float InvMax = 1.0f / 65535F; + private const float InvMax = 1f / 65535f; + /// + /// Initializes a new instance of the class. + /// /// The number of bits per sample for each pixel. /// The RGB color lookup table to use for decoding the image. public PaletteTiffColor(TiffBitsPerSample bitsPerSample, ushort[] colorMap) @@ -32,7 +35,7 @@ internal class PaletteTiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -49,7 +52,7 @@ internal class PaletteTiffColor : TiffBaseColorDecoder private static TPixel[] GeneratePalette(ushort[] colorMap, int colorCount) { - var palette = new TPixel[colorCount]; + TPixel[] palette = new TPixel[colorCount]; const int rOffset = 0; int gOffset = colorCount; @@ -60,7 +63,7 @@ internal class PaletteTiffColor : TiffBaseColorDecoder float r = colorMap[rOffset + i] * InvMax; float g = colorMap[gOffset + i] * InvMax; float b = colorMap[bOffset + i] * InvMax; - palette[i].FromScaledVector4(new Vector4(r, g, b, 1.0f)); + palette[i] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } return palette; diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs index 8ca45c9392..d8520e307e 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb161616TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,11 +10,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 16 bits for each channel. /// +/// The type of pixel format. internal class Rgb161616TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly bool isBigEndian; - private readonly Configuration configuration; /// @@ -32,10 +31,6 @@ internal class Rgb161616TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) @@ -46,14 +41,14 @@ internal class Rgb161616TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs index 08fb6d8bea..f55d7225e0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb16PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 16 bit. /// +/// The type of pixel format. internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,10 +26,6 @@ internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -42,26 +38,26 @@ internal class Rgb16PlanarTiffColor : TiffBasePlanarColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(blueData.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); offset += 2; - pixelRow[x] = TiffUtils.ColorFromRgb64(rgba, r, g, b, color); + pixelRow[x] = TPixel.FromRgb48(new(r, g, b)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs index 027dcce3bd..074c085301 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb242424TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 24 bits for each channel. /// +/// The type of pixel format. internal class Rgb242424TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class Rgb242424TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -41,18 +39,18 @@ internal class Rgb242424TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } else @@ -60,18 +58,18 @@ internal class Rgb242424TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs index eba29a7f70..03ee94c27a 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb24PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 24 bit. /// +/// The type of pixel format. internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,8 +26,6 @@ internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -45,15 +43,15 @@ internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } else @@ -61,15 +59,15 @@ internal class Rgb24PlanarTiffColor : TiffBasePlanarColorDecoder for (int x = 0; x < pixelRow.Length; x++) { redData.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); greenData.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); blueData.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs index 79f66c1431..5f04972595 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 32 bits for each channel. /// +/// The type of pixel format. internal class Rgb323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class Rgb323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; for (int y = top; y < top + height; y++) @@ -37,32 +35,32 @@ internal class Rgb323232TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs index 472697dd5e..caa6eb51d7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb32PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout for each color channel with 32 bit. /// +/// The type of pixel format. internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -26,9 +26,6 @@ internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder /// public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -41,26 +38,26 @@ internal class Rgb32PlanarTiffColor : TiffBasePlanarColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(blueData.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(r, g, b, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(r, g, b); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs index 7c6a4a0ec5..3a90e81746 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgb444TiffColor{TPixel}.cs @@ -9,17 +9,15 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation for 4 bits per color channel images. /// +/// The type of pixel format. internal class Rgb444TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; - var bgra = default(Bgra4444); for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y); @@ -31,9 +29,8 @@ internal class Rgb444TiffColor : TiffBaseColorDecoder offset++; byte b = (byte)((data[offset] & 0xF0) >> 4); - bgra.PackedValue = ToBgraPackedValue(b, g, r); - color.FromScaledVector4(bgra.ToScaledVector4()); - pixelRow[x] = color; + Bgra4444 bgra = new() { PackedValue = ToBgraPackedValue(b, g, r) }; + pixelRow[x] = TPixel.FromScaledVector4(bgra.ToScaledVector4()); if (x + 1 >= pixelRow.Length) { offset++; @@ -47,8 +44,7 @@ internal class Rgb444TiffColor : TiffBaseColorDecoder offset++; bgra.PackedValue = ToBgraPackedValue(b, g, r); - color.FromScaledVector4(bgra.ToScaledVector4()); - pixelRow[x + 1] = color; + pixelRow[x + 1] = TPixel.FromScaledVector4(bgra.ToScaledVector4()); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs index 1c3af55621..37605ef804 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbFloat323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 32 bits for each channel. /// +/// The type of pixel format. internal class RgbFloat323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +24,6 @@ internal class RgbFloat323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; @@ -52,9 +50,7 @@ internal class RgbFloat323232TiffColor : TiffBaseColorDecoder float b = BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(r, g, b, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } } else @@ -70,9 +66,7 @@ internal class RgbFloat323232TiffColor : TiffBaseColorDecoder float b = BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(r, g, b, 1.0f); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs index 0b822f5a0f..844b08d3c0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbPlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with 'Planar' layout (for all bit depths). /// +/// The type of pixel format. internal class RgbPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -49,11 +49,9 @@ internal class RgbPlanarTiffColor : TiffBasePlanarColorDecoder /// The height of the image block. public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var rBitReader = new BitReader(data[0].GetSpan()); - var gBitReader = new BitReader(data[1].GetSpan()); - var bBitReader = new BitReader(data[2].GetSpan()); + BitReader rBitReader = new(data[0].GetSpan()); + BitReader gBitReader = new(data[1].GetSpan()); + BitReader bBitReader = new(data[2].GetSpan()); for (int y = top; y < top + height; y++) { @@ -64,8 +62,7 @@ internal class RgbPlanarTiffColor : TiffBasePlanarColorDecoder float g = gBitReader.ReadBits(this.bitsPerSampleG) / this.gFactor; float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; - color.FromScaledVector4(new Vector4(r, g, b, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, 1f)); } rBitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs index dcaab94a6a..3c205d1476 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class RgbTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -40,9 +41,7 @@ internal class RgbTiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -53,8 +52,7 @@ internal class RgbTiffColor : TiffBaseColorDecoder float g = bitReader.ReadBits(this.bitsPerSampleG) / this.gFactor; float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; - color.FromScaledVector4(new Vector4(r, g, b, 1.0f)); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(r, g, b, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs index 0467f7ad5c..e4965887d6 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16161616TiffColor{TPixel}.cs @@ -13,6 +13,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 16 bits for each channel. /// +/// The type of pixel format. internal class Rgba16161616TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -29,8 +30,8 @@ internal class Rgba16161616TiffColor : TiffBaseColorDecoder /// /// The configuration. /// The memory allocator. - /// if set to true decodes the pixel data as big endian, otherwise as little endian. /// The type of the extra samples. + /// if set to true decodes the pixel data as big endian, otherwise as little endian. public Rgba16161616TiffColor(Configuration configuration, MemoryAllocator memoryAllocator, TiffExtraSampleType? extraSamplesType, bool isBigEndian) { this.configuration = configuration; @@ -42,15 +43,11 @@ internal class Rgba16161616TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; using IMemoryOwner vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null; - Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty; + Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : []; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); @@ -59,18 +56,18 @@ internal class Rgba16161616TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong g = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong b = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - ulong a = TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2)); offset += 2; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) : - TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorFromRgba64Premultiplied(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } else diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs index 7426544d29..3d36db17de 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba16PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 16 bit. /// +/// The type of pixel format. internal class Rgba16PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -33,10 +33,6 @@ internal class Rgba16PlanarTiffColor : TiffBasePlanarColorDecoder public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - Rgba64 rgba = TiffUtils.Rgba64Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -51,32 +47,32 @@ internal class Rgba16PlanarTiffColor : TiffBasePlanarColorDecoder(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); - ulong g = TiffUtils.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); - ulong b = TiffUtils.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); - ulong a = TiffUtils.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2)); + ushort r = TiffUtilities.ConvertToUShortLittleEndian(redData.Slice(offset, 2)); + ushort g = TiffUtilities.ConvertToUShortLittleEndian(greenData.Slice(offset, 2)); + ushort b = TiffUtilities.ConvertToUShortLittleEndian(blueData.Slice(offset, 2)); + ushort a = TiffUtilities.ConvertToUShortLittleEndian(alphaData.Slice(offset, 2)); offset += 2; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorFromRgba64Premultiplied(rgba, r, g, b, a, color) : - TiffUtils.ColorFromRgba64(rgba, r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorFromRgba64Premultiplied(r, g, b, a) + : TPixel.FromRgba64(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs index eba60679a2..a294693659 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24242424TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 24 bits for each channel. /// +/// The type of pixel format. internal class Rgba24242424TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +32,6 @@ internal class Rgba24242424TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; @@ -51,24 +48,24 @@ internal class Rgba24242424TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntBigEndian(buffer); + uint r = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntBigEndian(buffer); + uint g = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntBigEndian(buffer); + uint b = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntBigEndian(buffer); + uint a = TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } else @@ -76,24 +73,24 @@ internal class Rgba24242424TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong r = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint r = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong g = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint g = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong b = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint b = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; data.Slice(offset, 3).CopyTo(bufferSpan); - ulong a = TiffUtils.ConvertToUIntLittleEndian(buffer); + uint a = TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo24BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo24Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo24BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs index 1b842a79be..222e729867 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba24PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout for each color channel with 24 bit. /// +/// The type of pixel format. internal class Rgba24PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -33,8 +33,6 @@ internal class Rgba24PlanarTiffColor : TiffBasePlanarColorDecoder public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; @@ -54,19 +52,19 @@ internal class Rgba24PlanarTiffColor : TiffBasePlanarColorDecoder(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } else @@ -74,19 +72,19 @@ internal class Rgba24PlanarTiffColor : TiffBasePlanarColorDecoder(r, g, b, a) + : TiffUtilities.ColorScaleTo24Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs index 2193f2e817..5c57221d98 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel. /// +/// The type of pixel format. internal class Rgba32323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -32,9 +32,6 @@ internal class Rgba32323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; int offset = 0; @@ -46,42 +43,42 @@ internal class Rgba32323232TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - ulong a = TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong g = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong b = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - ulong a = TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs index 7d047cf7fd..8f90907418 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba32PlanarTiffColor{TPixel}.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -12,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and a 'Planar' layout for each color channel with 32 bit. /// +/// The type of pixel format. internal class Rgba32PlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { private readonly bool isBigEndian; - private readonly TiffExtraSampleType? extraSamplesType; /// @@ -33,9 +32,6 @@ internal class Rgba32PlanarTiffColor : TiffBasePlanarColorDecoder public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - Span redData = data[0].GetSpan(); Span greenData = data[1].GetSpan(); Span blueData = data[2].GetSpan(); @@ -50,32 +46,32 @@ internal class Rgba32PlanarTiffColor : TiffBasePlanarColorDecoder(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong r = TiffUtils.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); - ulong g = TiffUtils.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); - ulong b = TiffUtils.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); - ulong a = TiffUtils.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4)); + uint r = TiffUtilities.ConvertToUIntLittleEndian(redData.Slice(offset, 4)); + uint g = TiffUtilities.ConvertToUIntLittleEndian(greenData.Slice(offset, 4)); + uint b = TiffUtilities.ConvertToUIntLittleEndian(blueData.Slice(offset, 4)); + uint a = TiffUtilities.ConvertToUIntLittleEndian(alphaData.Slice(offset, 4)); offset += 4; - pixelRow[x] = hasAssociatedAlpha ? - TiffUtils.ColorScaleTo32BitPremultiplied(r, g, b, a, color) : - TiffUtils.ColorScaleTo32Bit(r, g, b, a, color); + pixelRow[x] = hasAssociatedAlpha + ? TiffUtilities.ColorScaleTo32BitPremultiplied(r, g, b, a) + : TiffUtilities.ColorScaleTo32Bit(r, g, b, a); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs index dc1fbb8717..26ffbbab9b 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/Rgba8888TiffColor{TPixel}.cs @@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and 8 bits per channel. /// +/// The type of pixel format. internal class Rgba8888TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -34,10 +35,8 @@ internal class Rgba8888TiffColor : TiffBaseColorDecoder int offset = 0; bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); using IMemoryOwner vectors = hasAssociatedAlpha ? this.memoryAllocator.Allocate(width) : null; - Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : Span.Empty; + Span vectorsSpan = hasAssociatedAlpha ? vectors.GetSpan() : []; for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs index 743502d56e..12f1b75b40 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaFloat32323232TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,6 +9,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 32 bits for each channel. /// +/// The type of pixel format. internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +24,6 @@ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); int offset = 0; Span buffer = stackalloc byte[4]; @@ -57,9 +55,7 @@ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder float a = BitConverter.ToSingle(buffer); offset += 4; - var colorVector = new Vector4(r, g, b, a); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a)); } } else @@ -78,9 +74,7 @@ internal class RgbaFloat32323232TiffColor : TiffBaseColorDecoder float a = BitConverter.ToSingle(data.Slice(offset, 4)); offset += 4; - var colorVector = new Vector4(r, g, b, a); - color.FromScaledVector4(colorVector); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(new(r, g, b, a)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs index 63aa64d867..7a599a06a7 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaPlanarTiffColor{TPixel}.cs @@ -12,6 +12,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with an alpha channel and with 'Planar' layout (for all bit depths). /// +/// The type of pixel format. internal class RgbaPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { @@ -59,13 +60,12 @@ internal class RgbaPlanarTiffColor : TiffBasePlanarColorDecoder /// The height of the image block. public override void Decode(IMemoryOwner[] data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); bool hasAssociatedAlpha = this.extraSampleType.HasValue && this.extraSampleType == TiffExtraSampleType.AssociatedAlphaData; - var rBitReader = new BitReader(data[0].GetSpan()); - var gBitReader = new BitReader(data[1].GetSpan()); - var bBitReader = new BitReader(data[2].GetSpan()); - var aBitReader = new BitReader(data[3].GetSpan()); + BitReader rBitReader = new(data[0].GetSpan()); + BitReader gBitReader = new(data[1].GetSpan()); + BitReader bBitReader = new(data[2].GetSpan()); + BitReader aBitReader = new(data[3].GetSpan()); for (int y = top; y < top + height; y++) { @@ -77,17 +77,15 @@ internal class RgbaPlanarTiffColor : TiffBasePlanarColorDecoder float b = bBitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; float a = aBitReader.ReadBits(this.bitsPerSampleA) / this.aFactor; - var vec = new Vector4(r, g, b, a); + Vector4 vector = new(r, g, b, a); if (hasAssociatedAlpha) { - color = TiffUtils.UnPremultiply(ref vec, color); + pixelRow[x] = TiffUtilities.UnPremultiply(ref vector); } else { - color.FromScaledVector4(vec); + pixelRow[x] = TPixel.FromScaledVector4(vector); } - - pixelRow[x] = color; } rBitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs index 0ea8a87fcc..68b59c95a4 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/RgbaTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'RGB' photometric interpretation with alpha channel (for all bit depths). /// +/// The type of pixel format. internal class RgbaTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -50,9 +51,7 @@ internal class RgbaTiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); bool hasAssociatedAlpha = this.extraSamplesType.HasValue && this.extraSamplesType == TiffExtraSampleType.AssociatedAlphaData; @@ -66,15 +65,14 @@ internal class RgbaTiffColor : TiffBaseColorDecoder float b = bitReader.ReadBits(this.bitsPerSampleB) / this.bFactor; float a = bitReader.ReadBits(this.bitsPerSampleB) / this.aFactor; - var vec = new Vector4(r, g, b, a); + Vector4 vector = new(r, g, b, a); if (hasAssociatedAlpha) { - pixelRow[x] = TiffUtils.UnPremultiply(ref vec, color); + pixelRow[x] = TiffUtilities.UnPremultiply(ref vector); } else { - color.FromScaledVector4(vec); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromScaledVector4(vector); } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs index f7fd55e523..6f1672e1b9 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero16TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 16-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,10 +25,6 @@ internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - L16 l16 = TiffUtils.L16Default; - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); - int offset = 0; for (int y = top; y < top + height; y++) { @@ -37,20 +33,20 @@ internal class WhiteIsZero16TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortBigEndian(data.Slice(offset, 2))); + ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortBigEndian(data.Slice(offset, 2))); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ushort intensity = (ushort)(ushort.MaxValue - TiffUtils.ConvertToUShortLittleEndian(data.Slice(offset, 2))); + ushort intensity = (ushort)(ushort.MaxValue - TiffUtilities.ConvertToUShortLittleEndian(data.Slice(offset, 2))); offset += 2; - pixelRow[x] = TiffUtils.ColorFromL16(l16, intensity, color); + pixelRow[x] = TPixel.FromL16(new(intensity)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs index 4cba8f2d72..1de9c295bb 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero1TiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for bilevel images). /// +/// The type of pixel format. internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -18,11 +19,9 @@ internal class WhiteIsZero1TiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { nuint offset = 0; - var colorBlack = default(TPixel); - var colorWhite = default(TPixel); + TPixel colorBlack = TPixel.FromRgba32(Color.Black.ToPixel()); + TPixel colorWhite = TPixel.FromRgba32(Color.White.ToPixel()); - colorBlack.FromRgba32(Color.Black.ToPixel()); - colorWhite.FromRgba32(Color.White.ToPixel()); ref byte dataRef = ref MemoryMarshal.GetReference(data); for (nuint y = (uint)top; y < (uint)(top + height); y++) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs index 59e0df87d2..94549d663d 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero24TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.Numerics; using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -11,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 24-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int bufferStartIdx = this.isBigEndian ? 1 : 0; const uint maxValue = 0xFFFFFF; @@ -41,10 +39,10 @@ internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(buffer); + uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } else @@ -52,10 +50,10 @@ internal class WhiteIsZero24TiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { data.Slice(offset, 3).CopyTo(bufferSpan); - ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(buffer); + uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(buffer); offset += 3; - pixelRow[x] = TiffUtils.ColorScaleTo24Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo24Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs index f3207b2f45..7d31f23abd 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero32FloatTiffColor{TPixel}.cs @@ -10,6 +10,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation for 32-bit float grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -24,8 +25,6 @@ internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); Span buffer = stackalloc byte[4]; int offset = 0; @@ -41,9 +40,7 @@ internal class WhiteIsZero32FloatTiffColor : TiffBaseColorDecoder : TiffBaseColorDecoder /// Implements the 'WhiteIsZero' photometric interpretation for 32-bit grayscale images. /// +/// The type of pixel format. internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -25,8 +25,6 @@ internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - color.FromScaledVector4(Vector4.Zero); const uint maxValue = 0xFFFFFFFF; int offset = 0; @@ -37,20 +35,20 @@ internal class WhiteIsZero32TiffColor : TiffBaseColorDecoder { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = maxValue - TiffUtils.ConvertToUIntBigEndian(data.Slice(offset, 4)); + uint intensity = maxValue - TiffUtilities.ConvertToUIntBigEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } else { for (int x = 0; x < pixelRow.Length; x++) { - ulong intensity = maxValue - TiffUtils.ConvertToUIntLittleEndian(data.Slice(offset, 4)); + uint intensity = maxValue - TiffUtilities.ConvertToUIntLittleEndian(data.Slice(offset, 4)); offset += 4; - pixelRow[x] = TiffUtils.ColorScaleTo32Bit(intensity, color); + pixelRow[x] = TiffUtilities.ColorScaleTo32Bit(intensity); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs index bc5e2fb645..7dcbe23c5f 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero4TiffColor{TPixel}.cs @@ -9,47 +9,30 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for 4-bit grayscale images). /// +/// The type of pixel format. internal class WhiteIsZero4TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; bool isOddWidth = (width & 1) == 1; - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRowSpan = pixels.DangerousGetRowSpan(y); for (int x = left; x < left + width - 1;) { byte byteData = data[offset++]; - - byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[x++] = color; - - byte intensity2 = (byte)((15 - (byteData & 0x0F)) * 17); - l8.PackedValue = intensity2; - color.FromL8(l8); - - pixelRowSpan[x++] = color; + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17))); + pixelRowSpan[x++] = TPixel.FromL8(new((byte)((15 - (byteData & 0x0F)) * 17))); } if (isOddWidth) { byte byteData = data[offset++]; - - byte intensity1 = (byte)((15 - ((byteData & 0xF0) >> 4)) * 17); - l8.PackedValue = intensity1; - color.FromL8(l8); - - pixelRowSpan[left + width - 1] = color; + pixelRowSpan[left + width - 1] = TPixel.FromL8(new((byte)((15 - ((byteData & 0xF0) >> 4)) * 17))); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs index fb2653543b..5429dbd3b0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZero8TiffColor{TPixel}.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats.Tiff.Utils; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; @@ -10,24 +9,21 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (optimized for 8-bit grayscale images). /// +/// The type of pixel format. internal class WhiteIsZero8TiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - int offset = 0; - - var l8 = default(L8); for (int y = top; y < top + height; y++) { Span pixelRow = pixels.DangerousGetRowSpan(y).Slice(left, width); for (int x = 0; x < pixelRow.Length; x++) { byte intensity = (byte)(byte.MaxValue - data[offset++]); - pixelRow[x] = TiffUtils.ColorFromL8(l8, intensity, color); + pixelRow[x] = TPixel.FromL8(new(intensity)); } } } diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs index b38868a0e4..0cd01a6199 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/WhiteIsZeroTiffColor{TPixel}.cs @@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements the 'WhiteIsZero' photometric interpretation (for all bit depths). /// +/// The type of pixel format. internal class WhiteIsZeroTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { private readonly ushort bitsPerSample0; - private readonly float factor; public WhiteIsZeroTiffColor(TiffBitsPerSample bitsPerSample) @@ -27,9 +27,7 @@ internal class WhiteIsZeroTiffColor : TiffBaseColorDecoder /// public override void Decode(ReadOnlySpan data, Buffer2D pixels, int left, int top, int width, int height) { - var color = default(TPixel); - - var bitReader = new BitReader(data); + BitReader bitReader = new(data); for (int y = top; y < top + height; y++) { @@ -37,10 +35,8 @@ internal class WhiteIsZeroTiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { int value = bitReader.ReadBits(this.bitsPerSample0); - float intensity = 1.0f - (value / this.factor); - - color.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1.0f)); - pixelRow[x] = color; + float intensity = 1f - (value / this.factor); + pixelRow[x] = TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f)); } bitReader.NextRow(); diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs index 791bfa438a..768177bfc0 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrPlanarTiffColor{TPixel}.cs @@ -11,11 +11,11 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'YCbCr' with the planar configuration. /// +/// The type of pixel format. internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder where TPixel : unmanaged, IPixel { private readonly YCbCrConverter converter; - private readonly ushort[] ycbcrSubSampling; public YCbCrPlanarTiffColor(Rational[] referenceBlackAndWhite, Rational[] coefficients, ushort[] ycbcrSubSampling) @@ -36,13 +36,12 @@ internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], cbData, crData); } - var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. - widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); + widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) @@ -51,8 +50,7 @@ internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(yData[offset], cbData[offset], crData[offset]); - color.FromRgba32(rgba); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgba32(rgba); offset++; } @@ -64,8 +62,8 @@ internal class YCbCrPlanarTiffColor : TiffBasePlanarColorDecoder { // If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively, // then the source data will be padded. - width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); - height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); + width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling); + height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling); for (int row = height - 1; row >= 0; row--) { diff --git a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs index 2e47698a67..5a13890356 100644 --- a/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs +++ b/src/ImageSharp/Formats/Tiff/PhotometricInterpretation/YCbCrTiffColor{TPixel}.cs @@ -11,6 +11,7 @@ namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation; /// /// Implements decoding pixel data with photometric interpretation of type 'YCbCr'. /// +/// The type of pixel format. internal class YCbCrTiffColor : TiffBaseColorDecoder where TPixel : unmanaged, IPixel { @@ -50,13 +51,12 @@ internal class YCbCrTiffColor : TiffBaseColorDecoder private void DecodeYCbCrData(Buffer2D pixels, int left, int top, int width, int height, ReadOnlySpan ycbcrData) { - var color = default(TPixel); int offset = 0; int widthPadding = 0; if (this.ycbcrSubSampling != null) { // Round to the next integer multiple of horizontalSubSampling. - widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); + widthPadding = TiffUtilities.PaddingToNextInteger(width, this.ycbcrSubSampling[0]); } for (int y = top; y < top + height; y++) @@ -65,8 +65,7 @@ internal class YCbCrTiffColor : TiffBaseColorDecoder for (int x = 0; x < pixelRow.Length; x++) { Rgba32 rgba = this.converter.ConvertToRgba32(ycbcrData[offset], ycbcrData[offset + 1], ycbcrData[offset + 2]); - color.FromRgba32(rgba); - pixelRow[x] = color; + pixelRow[x] = TPixel.FromRgba32(rgba); offset += 3; } @@ -78,8 +77,8 @@ internal class YCbCrTiffColor : TiffBaseColorDecoder { // If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively, // then the source data will be padded. - width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); - height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); + width += TiffUtilities.PaddingToNextInteger(width, horizontalSubSampling); + height += TiffUtilities.PaddingToNextInteger(height, verticalSubSampling); int blockWidth = width / horizontalSubSampling; int blockHeight = height / verticalSubSampling; int cbCrOffsetInBlock = horizontalSubSampling * verticalSubSampling; diff --git a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs index aed6d4ec66..63dc623995 100644 --- a/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs +++ b/src/ImageSharp/Formats/Tiff/TiffDecoderCore.cs @@ -163,8 +163,8 @@ internal class TiffDecoderCore : IImageDecoderInternals public Image Decode(BufferedReadStream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - List> frames = new(); - List framesMetadata = new(); + List> frames = []; + List framesMetadata = []; try { this.inputStream = stream; @@ -221,7 +221,7 @@ internal class TiffDecoderCore : IImageDecoderInternals DirectoryReader reader = new(stream, this.configuration.MemoryAllocator); IList directories = reader.Read(); - List framesMetadata = new(); + List framesMetadata = []; foreach (ExifProfile dir in directories) { framesMetadata.Add(this.CreateFrameMetadata(dir)); diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs new file mode 100644 index 0000000000..8b5e04f276 --- /dev/null +++ b/src/ImageSharp/Formats/Tiff/Utils/TiffUtilities.cs @@ -0,0 +1,120 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Buffers.Binary; +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Formats.Tiff.Utils; + +/// +/// Helper methods for TIFF decoding. +/// +internal static class TiffUtilities +{ + private const float Scale24Bit = 1f / 0xFFFFFF; + private static readonly Vector4 Scale24BitVector = Vector128.Create(Scale24Bit, Scale24Bit, Scale24Bit, 1f).AsVector4(); + + private const float Scale32Bit = 1f / 0xFFFFFFFF; + private static readonly Vector4 Scale32BitVector = Vector128.Create(Scale32Bit, Scale32Bit, Scale32Bit, 1f).AsVector4(); + + public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0); + + public static L16 L16Default { get; } = new(0); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ConvertToUShortBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static ushort ConvertToUShortLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertToUIntBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static uint ConvertToUIntLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorFromRgba64Premultiplied(ushort r, ushort g, ushort b, ushort a) + where TPixel : unmanaged, IPixel + { + if (a == 0) + { + return TPixel.FromRgba64(default); + } + + return TPixel.FromRgba64(new((ushort)(r / a), (ushort)(g / a), (ushort)(b / a), a)); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint r, uint g, uint b) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale24BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale24Bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24BitPremultiplied(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + { + Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; + return UnPremultiply(ref colorVector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint r, uint g, uint b) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, 1f) * Scale32BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(r, g, b, a) * Scale32Bit); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32BitPremultiplied(uint r, uint g, uint b, uint a) + where TPixel : unmanaged, IPixel + { + Vector4 vector = new Vector4(r, g, b, a) * Scale32Bit; + return UnPremultiply(ref vector); + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo24Bit(uint intensity) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale24BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel ColorScaleTo32Bit(uint intensity) + where TPixel : unmanaged, IPixel + => TPixel.FromScaledVector4(new Vector4(intensity, intensity, intensity, 1f) * Scale32BitVector); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TPixel UnPremultiply(ref Vector4 vector) + where TPixel : unmanaged, IPixel + { + Numerics.UnPremultiply(ref vector); + return TPixel.FromScaledVector4(vector); + } + + /// + /// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value. + /// + /// The width or height to round up. + /// The sub sampling. + /// The padding. + public static int PaddingToNextInteger(int valueToRoundUp, int subSampling) + { + if (valueToRoundUp % subSampling == 0) + { + return 0; + } + + return subSampling - (valueToRoundUp % subSampling); + } +} diff --git a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs b/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs deleted file mode 100644 index 7e0251af6d..0000000000 --- a/src/ImageSharp/Formats/Tiff/Utils/TiffUtils.cs +++ /dev/null @@ -1,176 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Buffers.Binary; -using System.Numerics; -using System.Runtime.CompilerServices; -using SixLabors.ImageSharp.PixelFormats; - -namespace SixLabors.ImageSharp.Formats.Tiff.Utils; - -/// -/// Helper methods for TIFF decoding. -/// -internal static class TiffUtils -{ - private const float Scale24Bit = 1.0f / 0xFFFFFF; - - private const float Scale32Bit = 1.0f / 0xFFFFFFFF; - - public static Rgba64 Rgba64Default { get; } = new(0, 0, 0, 0); - - public static L16 L16Default { get; } = new(0); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ConvertToUShortBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16BigEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static ushort ConvertToUShortLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt16LittleEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ConvertToUIntBigEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32BigEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static uint ConvertToUIntLittleEndian(ReadOnlySpan buffer) => BinaryPrimitives.ReadUInt32LittleEndian(buffer); - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromL8(L8 l8, byte intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - l8.PackedValue = intensity; - color.FromL8(l8); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgb64(Rgba64 rgba, ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (0xfffful << 48); - color.FromRgba64(rgba); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgba64(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48); - color.FromRgba64(rgba); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromRgba64Premultiplied(Rgba64 rgba, ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - rgba.PackedValue = r | (g << 16) | (b << 32) | (a << 48); - var vec = rgba.ToVector4(); - return UnPremultiply(ref vec, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(r * Scale24Bit, g * Scale24Bit, b * Scale24Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale24Bit; - return UnPremultiply(ref colorVector, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(r * Scale32Bit, g * Scale32Bit, b * Scale32Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit; - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32BitPremultiplied(ulong r, ulong g, ulong b, ulong a, TPixel color) - where TPixel : unmanaged, IPixel - { - Vector4 colorVector = new Vector4(r, g, b, a) * Scale32Bit; - return UnPremultiply(ref colorVector, color); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorFromL16(L16 l16, ushort intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - l16.PackedValue = intensity; - color.FromL16(l16); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo24Bit(ulong intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(intensity * Scale24Bit, intensity * Scale24Bit, intensity * Scale24Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel ColorScaleTo32Bit(ulong intensity, TPixel color) - where TPixel : unmanaged, IPixel - { - var colorVector = new Vector4(intensity * Scale32Bit, intensity * Scale32Bit, intensity * Scale32Bit, 1.0f); - color.FromScaledVector4(colorVector); - return color; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static TPixel UnPremultiply(ref Vector4 vector, TPixel color) - where TPixel : unmanaged, IPixel - { - Numerics.UnPremultiply(ref vector); - color.FromScaledVector4(vector); - - return color; - } - - /// - /// Finds the padding needed to round 'valueToRoundUp' to the next integer multiple of subSampling value. - /// - /// The width or height to round up. - /// The sub sampling. - /// The padding. - public static int PaddingToNextInteger(int valueToRoundUp, int subSampling) - { - if (valueToRoundUp % subSampling == 0) - { - return 0; - } - - return subSampling - (valueToRoundUp % subSampling); - } -} diff --git a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs index 3eb03b1724..65d5b65e88 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/WebpLossyDecoder.cs @@ -140,7 +140,6 @@ internal sealed class WebpLossyDecoder private static void DecodePixelValues(int width, int height, Span pixelData, Buffer2D decodedPixels, IMemoryOwner alpha) where TPixel : unmanaged, IPixel { - TPixel color = default; Span alphaSpan = alpha.Memory.Span; Span pixelsBgr = MemoryMarshal.Cast(pixelData); for (int y = 0; y < height; y++) @@ -151,8 +150,7 @@ internal sealed class WebpLossyDecoder { int offset = yMulWidth + x; Bgr24 bgr = pixelsBgr[offset]; - color.FromBgra32(new Bgra32(bgr.R, bgr.G, bgr.B, alphaSpan[offset])); - decodedPixelRow[x] = color; + decodedPixelRow[x] = TPixel.FromBgra32(new(bgr.R, bgr.G, bgr.B, alphaSpan[offset])); } } } diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index f9d88deacd..f473ce248e 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -43,96 +43,96 @@ public interface IPixel : IPixel, IEquatable /// The . static abstract TSelf FromVector4(Vector4 source); + /// + /// Initializes the pixel instance from an value. + /// + /// The value. + /// The . + static abstract TSelf FromAbgr32(Abgr32 source); + /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromArgb32(Argb32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromArgb32(Argb32 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromBgra5551(Bgra5551 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromBgra5551(Bgra5551 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromBgr24(Bgr24 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromBgr24(Bgr24 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromBgra32(Bgra32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); - - /// - /// Initializes the pixel instance from an value. - /// - /// The value. - /// The . - static virtual TSelf FromAbgr32(Abgr32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromBgra32(Bgra32 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromL8(L8 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromL8(L8 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromL16(L16 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromL16(L16 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromLa16(La16 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromLa16(La16 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromLa32(La32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromLa32(La32 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromRgb24(Rgb24 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromRgb24(Rgb24 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromRgba32(Rgba32 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromRgba32(Rgba32 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromRgb48(Rgb48 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromRgb48(Rgb48 source); /// /// Initializes the pixel instance from an value. /// /// The value. /// The . - static virtual TSelf FromRgba64(Rgba64 source) => TSelf.FromScaledVector4(source.ToScaledVector4()); + static abstract TSelf FromRgba64(Rgba64 source); #pragma warning restore CA1000 // Do not declare static members on generic types } @@ -145,7 +145,7 @@ public interface IPixel /// Convert the pixel instance into representation. /// /// The - virtual Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToVector4()); + Rgba32 ToRgba32(); /// /// Expands the pixel into a generic ("scaled") representation diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs index 0792306760..f62d3c6761 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.cs @@ -38,9 +38,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -143,9 +141,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -248,9 +244,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -353,9 +347,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -458,9 +450,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -563,9 +553,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -668,9 +656,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -773,9 +759,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -878,9 +862,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrc(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -983,9 +965,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1088,9 +1068,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1193,9 +1171,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1298,9 +1274,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1403,9 +1377,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1508,9 +1480,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1613,9 +1583,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1718,9 +1686,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1823,9 +1789,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -1928,9 +1892,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2033,9 +1995,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2138,9 +2098,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2243,9 +2201,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2348,9 +2304,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2453,9 +2407,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2558,9 +2510,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2663,9 +2613,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2768,9 +2716,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2873,9 +2819,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -2978,9 +2922,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3083,9 +3025,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3188,9 +3128,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3293,9 +3231,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3398,9 +3334,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3503,9 +3437,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3608,9 +3540,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3713,9 +3643,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3818,9 +3746,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -3923,9 +3849,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4028,9 +3952,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4133,9 +4055,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4238,9 +4158,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4343,9 +4261,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4448,9 +4364,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4553,9 +4467,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlaySrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4658,9 +4570,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightSrcOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4763,9 +4673,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4868,9 +4776,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -4973,9 +4879,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5078,9 +4982,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5183,9 +5085,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5288,9 +5188,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5393,9 +5291,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5498,9 +5394,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5603,9 +5497,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDest(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5708,9 +5600,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5813,9 +5703,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -5918,9 +5806,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6023,9 +5909,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6128,9 +6012,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6233,9 +6115,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6338,9 +6218,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6443,9 +6321,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6548,9 +6424,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestAtop(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6653,9 +6527,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6758,9 +6630,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6863,9 +6733,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -6968,9 +6836,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7073,9 +6939,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7178,9 +7042,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7283,9 +7145,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7388,9 +7248,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7493,9 +7351,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestOver(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7598,9 +7454,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7703,9 +7557,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7808,9 +7660,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -7913,9 +7763,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8018,9 +7866,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8123,9 +7969,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8228,9 +8072,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8333,9 +8175,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8438,9 +8278,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestIn(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8543,9 +8381,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8648,9 +8484,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8753,9 +8587,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8858,9 +8690,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -8963,9 +8793,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9068,9 +8896,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9173,9 +8999,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9278,9 +9102,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9383,9 +9205,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightDestOut(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9488,9 +9308,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9593,9 +9411,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9698,9 +9514,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9803,9 +9617,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -9908,9 +9720,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10013,9 +9823,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10118,9 +9926,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10223,9 +10029,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10328,9 +10132,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightClear(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10433,9 +10235,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.NormalXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10538,9 +10338,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.MultiplyXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10643,9 +10441,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.AddXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10748,9 +10544,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.SubtractXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10853,9 +10647,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.ScreenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -10958,9 +10750,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.DarkenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11063,9 +10853,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.LightenXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11168,9 +10956,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.OverlayXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// @@ -11273,9 +11059,7 @@ internal static class DefaultPixelBlenders /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.HardLightXor(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt index da6208eaa2..5b71bb0a64 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/DefaultPixelBlenders.Generated.tt @@ -81,9 +81,7 @@ var blenders = new []{ /// public override TPixel Blend(TPixel background, TPixel source, float amount) { - TPixel dest = default; - dest.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); - return dest; + return TPixel.FromScaledVector4(PorterDuffFunctions.<#=blender_composer#>(background.ToScaledVector4(), source.ToScaledVector4(), Numerics.Clamp(amount, 0, 1))); } /// diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs index e7cf3b2921..255bafc798 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.cs @@ -355,9 +355,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -373,9 +371,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -391,9 +387,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -409,9 +403,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -427,9 +419,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -445,9 +435,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -463,9 +451,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -481,9 +467,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -499,9 +483,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -517,9 +499,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -535,9 +515,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -553,9 +531,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(NormalXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -900,9 +876,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -918,9 +892,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -936,9 +908,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -954,9 +924,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -972,9 +940,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -990,9 +956,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1008,9 +972,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1026,9 +988,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1044,9 +1004,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1062,9 +1020,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1080,9 +1036,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1098,9 +1052,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(MultiplyXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1445,9 +1397,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1463,9 +1413,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1481,9 +1429,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1499,9 +1445,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1517,9 +1461,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1535,9 +1477,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1553,9 +1493,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1571,9 +1509,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1589,9 +1525,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1607,9 +1541,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1625,9 +1557,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1643,9 +1573,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(AddXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -1990,9 +1918,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2008,9 +1934,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2026,9 +1950,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2044,9 +1966,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2062,9 +1982,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2080,9 +1998,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2098,9 +2014,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2116,9 +2030,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2134,9 +2046,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2152,9 +2062,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2170,9 +2078,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2188,9 +2094,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(SubtractXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2535,9 +2439,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2553,9 +2455,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2571,9 +2471,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2589,9 +2487,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2607,9 +2503,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2625,9 +2519,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2643,9 +2535,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2661,9 +2551,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2679,9 +2567,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2697,9 +2583,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2715,9 +2599,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -2733,9 +2615,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(ScreenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3080,9 +2960,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3098,9 +2976,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3116,9 +2992,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3134,9 +3008,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3152,9 +3024,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3170,9 +3040,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3188,9 +3056,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3206,9 +3072,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3224,9 +3088,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3242,9 +3104,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3260,9 +3120,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3278,9 +3136,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(DarkenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3625,9 +3481,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3643,9 +3497,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3661,9 +3513,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3679,9 +3529,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3697,9 +3545,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3715,9 +3561,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3733,9 +3577,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3751,9 +3593,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3769,9 +3609,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3787,9 +3625,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3805,9 +3641,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -3823,9 +3657,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(LightenXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4170,9 +4002,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4188,9 +4018,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4206,9 +4034,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4224,9 +4050,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4242,9 +4066,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlaySrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4260,9 +4082,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4278,9 +4098,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4296,9 +4114,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4314,9 +4130,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4332,9 +4146,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4350,9 +4162,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4368,9 +4178,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(OverlayXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4715,9 +4523,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrc(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4733,9 +4539,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4751,9 +4555,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4769,9 +4571,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4787,9 +4587,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightSrcOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4805,9 +4603,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDest(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4823,9 +4619,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestAtop(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4841,9 +4635,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestOver(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4859,9 +4651,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestIn(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4877,9 +4667,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightDestOut(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4895,9 +4683,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightClear(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } /// @@ -4913,8 +4699,6 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(HardLightXor(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } } diff --git a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt index 64eee502bb..150adb33a8 100644 --- a/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelBlenders/PorterDuffFunctions.Generated.tt @@ -368,9 +368,7 @@ internal static partial class PorterDuffFunctions where TPixel : unmanaged, IPixel { opacity = Numerics.Clamp(opacity, 0, 1); - TPixel dest = default; - dest.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); - return dest; + return TPixel.FromScaledVector4(<#=blender#><#=composer#>(backdrop.ToScaledVector4(), source.ToScaledVector4(), opacity)); } <# } #> <# diff --git a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs index 9db3d30045..25fc74e08f 100644 --- a/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs +++ b/src/ImageSharp/PixelFormats/PixelConversionModifiers.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using SixLabors.ImageSharp.ColorSpaces.Companding; @@ -7,9 +7,9 @@ namespace SixLabors.ImageSharp.PixelFormats; /// /// Flags responsible to select additional operations which could be efficiently applied in -/// +/// /// or -/// +/// /// knowing the pixel type. /// [Flags] @@ -21,7 +21,7 @@ public enum PixelConversionModifiers None = 0, /// - /// Select and instead the standard (non scaled) variants. + /// Select and instead the standard (non scaled) variants. /// Scale = 1 << 0, diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index 9311c077da..fdf7ccb407 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -87,19 +87,23 @@ public partial struct A8 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static A8 FromArgb32(Argb32 source) => new(source.A); + public static A8 FromAbgr32(Abgr32 source) => new(source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static A8 FromBgr24(Bgr24 source) => new(byte.MaxValue); + public static A8 FromArgb32(Argb32 source) => new(source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static A8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static A8 FromBgra32(Bgra32 source) => new(source.A); + public static A8 FromBgr24(Bgr24 source) => new(byte.MaxValue); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static A8 FromAbgr32(Abgr32 source) => new(source.A); + public static A8 FromBgra32(Bgra32 source) => new(source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 2a29292a0c..65354c807f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -92,7 +92,9 @@ public partial struct Abgr32 : IPixel, IPackedVector /// The alpha component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(float r, float g, float b, float a = 1) - : this() => Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -102,7 +104,9 @@ public partial struct Abgr32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector3 vector) - : this() => Pack(vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -112,7 +116,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Abgr32(Vector4 vector) - : this() => Pack(vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -170,7 +174,7 @@ public partial struct Abgr32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + public readonly Rgba32 ToRgba32() => Rgba32.FromAbgr32(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -204,11 +208,15 @@ public partial struct Abgr32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Abgr32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + public static Abgr32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Abgr32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Abgr32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + public static Abgr32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 51ef76ad6b..50557880a0 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -85,7 +85,9 @@ public partial struct Argb32 : IPixel, IPackedVector /// The alpha component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(float r, float g, float b, float a = 1) - : this() => Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -95,7 +97,9 @@ public partial struct Argb32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector3 vector) - : this() => Pack(vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -105,7 +109,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Argb32(Vector4 vector) - : this() => Pack(vector); + : this() => this = Pack(vector); /// /// Initializes a new instance of the struct. @@ -163,7 +167,7 @@ public partial struct Argb32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + public readonly Rgba32 ToRgba32() => Rgba32.FromArgb32(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -193,19 +197,23 @@ public partial struct Argb32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Argb32 FromArgb32(Argb32 source) => new() { PackedValue = source.PackedValue }; + public static Argb32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Argb32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + public static Argb32 FromArgb32(Argb32 source) => new() { PackedValue = source.PackedValue }; + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Argb32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Argb32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); + public static Argb32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Argb32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); + public static Argb32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -276,23 +284,6 @@ public partial struct Argb32 : IPixel, IPackedVector /// public override readonly int GetHashCode() => this.Argb.GetHashCode(); - /// - /// Packs the four floats into a color. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Argb32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); - - /// - /// Packs a into a uint. - /// - /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Argb32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1f)); - /// /// Packs a into a color. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 4756f5e199..12e6736b71 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -15,37 +15,44 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The red component. -/// The green component. -/// The blue component. [StructLayout(LayoutKind.Explicit)] -[method: MethodImpl(MethodImplOptions.AggressiveInlining)] -public partial struct Bgr24(byte r, byte g, byte b) : IPixel +public partial struct Bgr24 : IPixel { /// /// The blue component. /// [FieldOffset(0)] - public byte B = b; + public byte B; /// /// The green component. /// [FieldOffset(1)] - public byte G = g; + public byte G; /// /// The red component. /// [FieldOffset(2)] - public byte R = r; + public byte R; private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Bgr24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + /// /// Compares two objects for equality. /// @@ -70,7 +77,7 @@ public partial struct Bgr24(byte r, byte g, byte b) : IPixel /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B); + public readonly Rgba32 ToRgba32() => Rgba32.FromBgr24(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -106,10 +113,18 @@ public partial struct Bgr24(byte r, byte g, byte b) : IPixel return new(result.GetElement(0), result.GetElement(4), result.GetElement(8)); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr24 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); @@ -146,10 +161,6 @@ public partial struct Bgr24(byte r, byte g, byte b) : IPixel [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr24 FromRgb24(Rgb24 source) => new(source.R, source.G, source.B); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bgr24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr24 FromRgba32(Rgba32 source) => new(source.R, source.G, source.B); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index 4ea149dda9..fe26bb8fd1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -75,6 +75,9 @@ public partial struct Bgr565(Vector3 vector) : IPixel, IPackedVector public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + /// + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgr565 FromScaledVector4(Vector4 source) => FromVector4(source); @@ -83,6 +86,58 @@ public partial struct Bgr565(Vector3 vector) : IPixel, IPackedVector new() { PackedValue = Pack(new Vector3(source.X, source.Y, source.Z)) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgr565 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index aeffd57602..fc5d55e64c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -116,7 +116,7 @@ public partial struct Bgra32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + public readonly Rgba32 ToRgba32() => Rgba32.FromBgra32(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -146,11 +146,15 @@ public partial struct Bgra32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bgra32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + public static Bgra32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bgra32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); + public static Bgra32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index baaa49ce11..4c89d8e944 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the components for the packed vector. -public partial struct Bgra4444(Vector4 vector) : IPixel, IPackedVector +public partial struct Bgra4444 : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -30,8 +26,14 @@ public partial struct Bgra4444(Vector4 vector) : IPixel, IPackedVector { } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the components for the packed vector. + public Bgra4444(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public ushort PackedValue { get; set; } = Pack(vector); + public ushort PackedValue { get; set; } /// /// Compares two objects for equality. @@ -55,6 +57,10 @@ public partial struct Bgra4444(Vector4 vector) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra4444 left, Bgra4444 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); @@ -90,6 +96,58 @@ public partial struct Bgra4444(Vector4 vector) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Bgra4444 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra4444 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is Bgra4444 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index 381f4628f0..fde937fb54 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -13,13 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// -/// The vector containing the components for the packed vector. -/// -public partial struct Bgra5551(Vector4 vector) : IPixel, IPackedVector +public partial struct Bgra5551 : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -33,8 +27,16 @@ public partial struct Bgra5551(Vector4 vector) : IPixel, IPackedVector { } + /// + /// Initializes a new instance of the struct. + /// + /// + /// The vector containing the components for the packed vector. + /// + public Bgra5551(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public ushort PackedValue { get; set; } = Pack(vector); + public ushort PackedValue { get; set; } /// /// Compares two objects for equality. @@ -58,6 +60,10 @@ public partial struct Bgra5551(Vector4 vector) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Bgra5551 left, Bgra5551 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); @@ -90,7 +96,55 @@ public partial struct Bgra5551(Vector4 vector) : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Bgra5551 FromBgra5551(Bgra5551 source) => new() { PackedValue = source.PackedValue }; + public static Bgra5551 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Bgra5551 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object? obj) => obj is Bgra5551 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index fba3206728..8b4384ff7f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -15,19 +15,8 @@ namespace SixLabors.ImageSharp.PixelFormats; /// public partial struct Byte4 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); - /// - /// Initializes a new instance of the struct. - /// - /// - /// A vector containing the initial values for the components of the Byte4 structure. - /// - public Byte4(Vector4 vector) => this.PackedValue = Pack(vector); - /// /// Initializes a new instance of the struct. /// @@ -36,11 +25,18 @@ public partial struct Byte4 : IPixel, IPackedVector /// The z-component /// The w-component public Byte4(float x, float y, float z, float w) + : this(new Vector4(x, y, z, w)) { - Vector4 vector = new(x, y, z, w); - this.PackedValue = Pack(vector); } + /// + /// Initializes a new instance of the struct. + /// + /// + /// A vector containing the initial values for the components of the Byte4 structure. + /// + public Byte4(Vector4 vector) => this.PackedValue = Pack(vector); + /// public uint PackedValue { get; set; } @@ -100,10 +96,58 @@ public partial struct Byte4 : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Byte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Byte4 FromRgba32(Rgba32 source) => new() { PackedValue = source.PackedValue }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Byte4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is Byte4 byte4 && this.Equals(byte4); @@ -130,12 +174,10 @@ public partial struct Byte4 : IPixel, IPackedVector { vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); - Vector128 result = Vector128.ConvertToUInt32(vector.AsVector128()); - - uint byte4 = result.GetElement(0) & 0xFF; - uint byte3 = result.GetElement(1) << 8; - uint byte2 = result.GetElement(2) << 16; - uint byte1 = result.GetElement(3) << 24; + uint byte4 = (uint)Math.Round(vector.X) & 0xFF; + uint byte3 = ((uint)Math.Round(vector.Y) & 0xFF) << 0x8; + uint byte2 = ((uint)Math.Round(vector.Z) & 0xFF) << 0x10; + uint byte1 = ((uint)Math.Round(vector.W) & 0xFF) << 0x18; return byte4 | byte3 | byte2 | byte1; } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 2d8ab5ff08..45cc061ae4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -12,14 +12,16 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, 0, 0, 1] to [1, 0, 0, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The single component value. -public partial struct HalfSingle(float value) : IPixel, IPackedVector +public partial struct HalfSingle : IPixel, IPackedVector { + /// + /// Initializes a new instance of the struct. + /// + /// The single component value. + public HalfSingle(float value) => this.PackedValue = HalfTypeHelper.Pack(value); + /// - public ushort PackedValue { get; set; } = HalfTypeHelper.Pack(value); + public ushort PackedValue { get; set; } /// /// Compares two objects for equality. @@ -43,6 +45,10 @@ public partial struct HalfSingle(float value) : IPixel, IPackedVecto [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfSingle left, HalfSingle right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -80,6 +86,58 @@ public partial struct HalfSingle(float value) : IPixel, IPackedVecto [MethodImpl(MethodImplOptions.AggressiveInlining)] public static HalfSingle FromVector4(Vector4 source) => new() { PackedValue = HalfTypeHelper.Pack(source.X) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfSingle FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 525638b1da..1fd3125231 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -52,6 +52,10 @@ public partial struct HalfVector2 : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector2 left, HalfVector2 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -93,6 +97,58 @@ public partial struct HalfVector2 : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static HalfVector2 FromVector4(Vector4 source) => new() { PackedValue = Pack(source.X, source.Y) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 28f3849ebe..4741bcf9e4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// A vector containing the initial values for the components -public partial struct HalfVector4(Vector4 vector) : IPixel, IPackedVector +public partial struct HalfVector4 : IPixel, IPackedVector { /// /// Initializes a new instance of the struct. @@ -30,8 +26,14 @@ public partial struct HalfVector4(Vector4 vector) : IPixel, IPacked { } + /// + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components + public HalfVector4(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public ulong PackedValue { get; set; } = Pack(vector); + public ulong PackedValue { get; set; } /// /// Compares two objects for equality. @@ -55,13 +57,17 @@ public partial struct HalfVector4(Vector4 vector) : IPixel, IPacked [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(HalfVector4 left, HalfVector4 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() { Vector4 scaled = this.ToVector4(); scaled += Vector4.One; - scaled /= 2F; + scaled /= 2f; return scaled; } @@ -87,7 +93,7 @@ public partial struct HalfVector4(Vector4 vector) : IPixel, IPacked [MethodImpl(MethodImplOptions.AggressiveInlining)] public static HalfVector4 FromScaledVector4(Vector4 source) { - source *= 2F; + source *= 2f; source -= Vector4.One; return FromVector4(source); } @@ -96,6 +102,58 @@ public partial struct HalfVector4(Vector4 vector) : IPixel, IPacked [MethodImpl(MethodImplOptions.AggressiveInlining)] public static HalfVector4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static HalfVector4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is HalfVector4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 52bb85fe27..41578a6f60 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -12,16 +12,18 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The luminance component -public partial struct L16(ushort luminance) : IPixel, IPackedVector +public partial struct L16 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component + public L16(ushort luminance) => this.PackedValue = luminance; + /// - public ushort PackedValue { get; set; } = luminance; + public ushort PackedValue { get; set; } /// /// Compares two objects for equality. @@ -85,19 +87,23 @@ public partial struct L16(ushort luminance) : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L16 FromArgb32(Argb32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + public static L16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + public static L16 FromArgb32(Argb32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + public static L16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); + public static L16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 7c47ab10cc..90731f6e97 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -13,24 +13,19 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The luminance component. -public partial struct L8(byte luminance) : IPixel, IPackedVector +public partial struct L8 : IPixel, IPackedVector { - /// - /// The maximum byte value. - /// private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); /// - /// The half vector value. + /// Initializes a new instance of the struct. /// - private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + /// The luminance component. + public L8(byte luminance) => this.PackedValue = luminance; /// - public byte PackedValue { get; set; } = luminance; + public byte PackedValue { get; set; } /// /// Compares two objects for equality. @@ -94,19 +89,23 @@ public partial struct L8(byte luminance) : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L8 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + public static L8 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L8 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + public static L8 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static L8 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L8 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + public static L8 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static L8 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); + public static L8 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 558f15332a..948f0b1443 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -14,13 +14,8 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The luminance component. -/// The alpha component. [StructLayout(LayoutKind.Explicit)] -public partial struct La16(byte l, byte a) : IPixel, IPackedVector +public partial struct La16 : IPixel, IPackedVector { /// /// The maximum byte value. @@ -36,13 +31,24 @@ public partial struct La16(byte l, byte a) : IPixel, IPackedVector /// Gets or sets the luminance component. /// [FieldOffset(0)] - public byte L = l; + public byte L; /// /// Gets or sets the alpha component. /// [FieldOffset(1)] - public byte A = a; + public byte A; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component. + /// The alpha component. + public La16(byte l, byte a) + { + this.L = l; + this.A = a; + } /// public ushort PackedValue @@ -110,19 +116,23 @@ public partial struct La16(byte l, byte a) : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La16 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); + public static La16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); + public static La16 FromArgb32(Argb32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La16 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); + public static La16 FromBgr24(Bgr24 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), byte.MaxValue); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La16 FromAbgr32(Abgr32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); + public static La16 FromBgra32(Bgra32 source) => new(ColorNumerics.Get8BitBT709Luminance(source.R, source.G, source.B), source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index c0d0243563..0381973d9c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -13,13 +13,8 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The luminance component. -/// The alpha component. [StructLayout(LayoutKind.Explicit)] -public partial struct La32(ushort l, ushort a) : IPixel, IPackedVector +public partial struct La32 : IPixel, IPackedVector { private const float Max = ushort.MaxValue; @@ -27,13 +22,24 @@ public partial struct La32(ushort l, ushort a) : IPixel, IPackedVector [FieldOffset(0)] - public ushort L = l; + public ushort L; /// /// Gets or sets the alpha component. /// [FieldOffset(2)] - public ushort A = a; + public ushort A; + + /// + /// Initializes a new instance of the struct. + /// + /// The luminance component. + /// The alpha component. + public La32(ushort l, ushort a) + { + this.L = l; + this.A = a; + } /// public uint PackedValue @@ -107,7 +113,7 @@ public partial struct La32(ushort l, ushort a) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La32 FromArgb32(Argb32 source) + public static La32 FromAbgr32(Abgr32 source) { ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); ushort a = ColorNumerics.From8BitTo16Bit(source.A); @@ -116,20 +122,24 @@ public partial struct La32(ushort l, ushort a) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La32 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); - - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La32 FromBgra32(Bgra32 source) + public static La32 FromArgb32(Argb32 source) { ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); ushort a = ColorNumerics.From8BitTo16Bit(source.A); return new(l, a); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static La32 FromAbgr32(Abgr32 source) + public static La32 FromBgr24(Bgr24 source) => new(ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B), ushort.MaxValue); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static La32 FromBgra32(Bgra32 source) { ushort l = ColorNumerics.Get16BitBT709Luminance(source.R, source.G, source.B); ushort a = ColorNumerics.From8BitTo16Bit(source.A); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index 138490b9cc..e901adc9e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct NormalizedByte2(Vector2 vector) : IPixel, IPackedVector +public partial struct NormalizedByte2 : IPixel, IPackedVector { private const float MaxPos = 127f; private static readonly Vector2 Half = new(MaxPos); @@ -32,8 +28,14 @@ public partial struct NormalizedByte2(Vector2 vector) : IPixel, { } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte2(Vector2 vector) => this.PackedValue = Pack(vector); + /// - public ushort PackedValue { get; set; } = Pack(vector); + public ushort PackedValue { get; set; } /// /// Compares two objects for equality. @@ -57,6 +59,10 @@ public partial struct NormalizedByte2(Vector2 vector) : IPixel, [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte2 left, NormalizedByte2 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -94,6 +100,58 @@ public partial struct NormalizedByte2(Vector2 vector) : IPixel, [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NormalizedByte2 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index d9a3cc1cd9..1202801abd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -13,11 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct NormalizedByte4(Vector4 vector) : IPixel, IPackedVector +public partial struct NormalizedByte4 : IPixel, IPackedVector { private const float MaxPos = 127f; private static readonly Vector4 Half = Vector128.Create(MaxPos).AsVector4(); @@ -35,8 +31,14 @@ public partial struct NormalizedByte4(Vector4 vector) : IPixel, { } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedByte4(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public uint PackedValue { get; set; } = Pack(vector); + public uint PackedValue { get; set; } /// /// Compares two objects for equality. @@ -60,6 +62,10 @@ public partial struct NormalizedByte4(Vector4 vector) : IPixel, [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(NormalizedByte4 left, NormalizedByte4 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -97,6 +103,58 @@ public partial struct NormalizedByte4(Vector4 vector) : IPixel, return FromVector4(source); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedByte4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static NormalizedByte4 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index 8971e9879e..e15cdafa74 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct NormalizedShort2(Vector2 vector) : IPixel, IPackedVector +public partial struct NormalizedShort2 : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -34,8 +30,14 @@ public partial struct NormalizedShort2(Vector2 vector) : IPixel + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort2(Vector2 vector) => this.PackedValue = Pack(vector); + /// - public uint PackedValue { get; set; } = Pack(vector); + public uint PackedValue { get; set; } /// /// Compares two objects for equality. @@ -59,6 +61,10 @@ public partial struct NormalizedShort2(Vector2 vector) : IPixel !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -96,6 +102,58 @@ public partial struct NormalizedShort2(Vector2 vector) : IPixel new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index 7271980763..f692f73b24 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -13,11 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-1, -1, -1, -1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct NormalizedShort4(Vector4 vector) : IPixel, IPackedVector +public partial struct NormalizedShort4 : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -36,8 +32,14 @@ public partial struct NormalizedShort4(Vector4 vector) : IPixel + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public NormalizedShort4(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public ulong PackedValue { get; set; } = Pack(vector); + public ulong PackedValue { get; set; } /// /// Compares two objects for equality. @@ -61,6 +63,10 @@ public partial struct NormalizedShort4(Vector4 vector) : IPixel !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -102,6 +108,58 @@ public partial struct NormalizedShort4(Vector4 vector) : IPixel new() { PackedValue = Pack(source) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static NormalizedShort4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is NormalizedShort4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs index 131191ee29..da0e6ec609 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/A8.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs index 17ca5edd81..d459fc4d6c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Abgr32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs index f2a5eb28b0..608d618d48 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Argb32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs index 05b198636f..36ffff7147 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr24.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs index 7217b7c0b0..87175fe21c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgr565.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs index 0d77f8566f..d2c2b2db74 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs index 5f516f0945..1a0be8b6ff 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra4444.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs index ea11e53095..3a2856125e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Bgra5551.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs index 0946dd4c78..c012547c95 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Byte4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs index f24ed6fae8..a5e4e3048b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Abgr32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Abgr32 internal partial class PixelOperations : PixelOperations { /// - public override void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToAbgr32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToAbgr32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs index 37ac39a851..30fed8d1c1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Argb32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Argb32 internal partial class PixelOperations : PixelOperations { /// - public override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToArgb32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToArgb32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToArgb32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs index f604d6f970..e3ff3a7fea 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgr24.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Bgr24 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgr24(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgr24(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgr24(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs index b9f7a49e11..ae6be44012 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra32.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Bgra32 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToBgra32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgra32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgra32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs index c1ba4f0618..9e877cb9de 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Bgra5551.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Bgra5551 internal partial class PixelOperations : PixelOperations { /// - public override void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToBgra5551(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToBgra5551(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToBgra5551(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs index c38d752ea6..21c7824560 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L16.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct L16 internal partial class PixelOperations : PixelOperations { /// - public override void FromL16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromL16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToL16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToL16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromL16(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToL16(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToL16(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs index 656a0546ba..6a7c458001 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/L8.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct L8 internal partial class PixelOperations : PixelOperations { /// - public override void FromL8(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromL8(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToL8(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToL8(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromL8(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToL8(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToL8(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs index 82be1323cd..2346f32e1b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La16.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct La16 internal partial class PixelOperations : PixelOperations { /// - public override void FromLa16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromLa16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToLa16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToLa16(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromLa16(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToLa16(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToLa16(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs index a9ee9d6b78..d949d61e0d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/La32.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct La32 internal partial class PixelOperations : PixelOperations { /// - public override void FromLa32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromLa32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToLa32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToLa32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromLa32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToLa32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToLa32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs index 1d87121e92..fd6465a22f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb24.PixelOperations.Generated.cs @@ -21,337 +21,316 @@ public partial struct Rgb24 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(PixelConversionModifiers.Scale | PixelConversionModifiers.Premultiply)); } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToRgba32(sourceBytes, destinationBytes); } /// public override void FromRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgb24(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgb24(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgb24(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs index 60cfdad4b6..69e06da219 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgb48.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Rgb48 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgb48(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgb48(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs index da7c9a6c91..8a98521f0b 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba32.PixelOperations.Generated.cs @@ -21,317 +21,296 @@ public partial struct Rgba32 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToArgb32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToArgb32(sourceBytes, destinationBytes); } /// public override void FromArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromArgb32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromArgb32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToAbgr32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToAbgr32(sourceBytes, destinationBytes); } /// public override void FromAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromAbgr32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromAbgr32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgra32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgra32(sourceBytes, destinationBytes); } /// public override void FromBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgra32.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgra32.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToRgb24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToRgb24(sourceBytes, destinationBytes); } /// public override void FromRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgb24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgb24.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromRgba32.ToBgr24(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromRgba32.ToBgr24(sourceBytes, destinationBytes); } /// public override void FromBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast(sourcePixels); - Span dest = MemoryMarshal.Cast(destinationPixels); - PixelConverter.FromBgr24.ToRgba32(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast(source); + Span destinationBytes = MemoryMarshal.Cast(destination); + PixelConverter.FromBgr24.ToRgba32(sourceBytes, destinationBytes); } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba64( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgba32(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgba32(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs index b6236f8a66..4679e950e5 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/Rgba64.PixelOperations.Generated.cs @@ -21,282 +21,246 @@ public partial struct Rgba64 internal partial class PixelOperations : PixelOperations { /// - public override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + public override void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + public override void ToRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// public override void ToArgb32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Argb32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToAbgr32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgr24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL8( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = L8.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToL16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = L16.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa16( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La16 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = La16.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToLa32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref La32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = La32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb24( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgba32( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToRgb48( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void ToBgra5551( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) { - PixelOperations.Instance.ToRgba64(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.ToRgba64(configuration, source, destination.Slice(0, source.Length)); } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude index f7e178d7f2..c4d5a6b95d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Generated/_Common.ttinclude @@ -57,10 +57,10 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span<<#=pixelType#>> destinationPixels) + ReadOnlySpan source, + Span<<#=pixelType#>> destination) { - PixelOperations.Instance.To<#=pixelType#>(configuration, sourcePixels, destinationPixels.Slice(0, sourcePixels.Length)); + PixelOperations.Instance.To<#=pixelType#>(configuration, source, destination.Slice(0, source.Length)); } <#+ } @@ -68,21 +68,21 @@ using SixLabors.ImageSharp.PixelFormats.Utils; void GenerateDefaultSelfConversionMethods(string pixelType) { #>/// - public override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destinationPixels) + public override void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - source.CopyTo(destinationPixels.Slice(0, source.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } /// - public override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> sourcePixels, Span<<#=pixelType#>> destinationPixels) + public override void To<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span<<#=pixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - sourcePixels.CopyTo(destinationPixels.Slice(0, sourcePixels.Length)); + source.CopyTo(destination.Slice(0, source.Length)); } <#+ } @@ -94,21 +94,18 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void To<#=toPixelType#>( Configuration configuration, - ReadOnlySpan<<#=fromPixelType#>> sourcePixels, - Span<<#=toPixelType#>> destinationPixels) + ReadOnlySpan<<#=fromPixelType#>> source, + Span<<#=toPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref <#=fromPixelType#> sourceRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=toPixelType#> destRef = ref MemoryMarshal.GetReference(destinationPixels); + ref <#=fromPixelType#> sourceBase = ref MemoryMarshal.GetReference(source); + ref <#=toPixelType#> destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref <#=fromPixelType#> sp = ref Unsafe.Add(ref sourceRef, i); - ref <#=toPixelType#> dp = ref Unsafe.Add(ref destRef, i); - - dp.From<#=fromPixelType#>(sp); + Unsafe.Add(ref destinationBase, i) = <#=toPixelType#>.From<#=fromPixelType#>(Unsafe.Add(ref sourceBase, i)); } } <#+ @@ -121,29 +118,29 @@ using SixLabors.ImageSharp.PixelFormats.Utils; /// public override void To<#=otherPixelType#>( Configuration configuration, - ReadOnlySpan<<#=thisPixelType#>> sourcePixels, - Span<<#=otherPixelType#>> destinationPixels) + ReadOnlySpan<<#=thisPixelType#>> source, + Span<<#=otherPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(sourcePixels); - Span dest = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(destinationPixels); - PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(source); + Span destinationBytes = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(destination); + PixelConverter.From<#=thisPixelType#>.To<#=otherPixelType#>(sourceBytes, destinationBytes); } /// public override void From<#=otherPixelType#>( Configuration configuration, - ReadOnlySpan<<#=otherPixelType#>> sourcePixels, - Span<<#=thisPixelType#>> destinationPixels) + ReadOnlySpan<<#=otherPixelType#>> source, + Span<<#=thisPixelType#>> destination) { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ReadOnlySpan source = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(sourcePixels); - Span dest = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(destinationPixels); - PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(source, dest); + ReadOnlySpan sourceBytes = MemoryMarshal.Cast<<#=otherPixelType#>, byte>(source); + Span destinationBytes = MemoryMarshal.Cast<<#=thisPixelType#>, byte>(destination); + PixelConverter.From<#=otherPixelType#>.To<#=thisPixelType#>(sourceBytes, destinationBytes); } <#+ } @@ -161,20 +158,20 @@ using SixLabors.ImageSharp.PixelFormats.Utils; public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span<<#=pixelType#>> destinationPixels, + Span<<#=pixelType#>> destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destinationPixels, modifiers.Remove(<#=removeTheseModifiers#>)); + Vector4Converters.RgbaCompatible.FromVector4(configuration, this, sourceVectors, destination, modifiers.Remove(<#=removeTheseModifiers#>)); } /// public override void ToVector4( Configuration configuration, - ReadOnlySpan<<#=pixelType#>> sourcePixels, - Span destVectors, + ReadOnlySpan<<#=pixelType#>> source, + Span destination, PixelConversionModifiers modifiers) { - Vector4Converters.RgbaCompatible.ToVector4(configuration, this, sourcePixels, destVectors, modifiers.Remove(<#=removeTheseModifiers#>)); + Vector4Converters.RgbaCompatible.ToVector4(configuration, this, source, destination, modifiers.Remove(<#=removeTheseModifiers#>)); } <#+ } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs index 8343b4b3c4..770f3a1de8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfSingle.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs index 9a2bdd2603..160ab9bd0f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs index 0590b43c8e..703138454e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/HalfVector4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs index fc7a81ae20..c9714c2170 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L16.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs index c97af4e347..e7b463fe08 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/L8.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs index 9be38ac4e0..316c965650 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La16.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs index 824618c658..34a8655338 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/La32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs index 848d0d6f3a..36f4a0bf55 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs index 79319070dc..e67321e4f4 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedByte4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs index 0b5f23bc58..99636cb376 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs index 21634a2b34..ad6aa8d8a8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/NormalizedShort4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs index e0e117727d..7bca1c781e 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rg32.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs index b4dd4fcc3e..435a8c0779 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb24.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs index 26f216ae23..c9ed730c47 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgb48.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index 36b9f85f77..ed89585dcf 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.PixelFormats; diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs index f796098c6d..6b362d44ec 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba64.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs index 128fd8dafd..5f9b51af90 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/RgbaVector.PixelOperations.cs @@ -2,9 +2,7 @@ // Licensed under the Six Labors Split License. using System.Numerics; -using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats.Utils; namespace SixLabors.ImageSharp.PixelFormats; @@ -55,43 +53,5 @@ public partial struct RgbaVector MemoryMarshal.Cast(sourcePixels).CopyTo(destinationVectors); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); } - - public override void ToL8( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); - - ref Vector4 sourceBaseRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); - ref L8 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); - - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L8 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.Pack(sp); - } - } - - public override void ToL16( - Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) - { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); - - ref Vector4 sourceBaseRef = ref Unsafe.As(ref MemoryMarshal.GetReference(sourcePixels)); - ref L16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); - - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) - { - ref Vector4 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.Pack(sp); - } - } } } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs index 737cd52993..d8225f18aa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short2.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs index ab069c0ab1..3d7043b0c8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Short4.PixelOperations.cs @@ -1,8 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using SixLabors.ImageSharp.Formats; - namespace SixLabors.ImageSharp.PixelFormats; /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index c31bfc6132..0dea025122 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 0, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct Rg32(Vector2 vector) : IPixel, IPackedVector +public partial struct Rg32 : IPixel, IPackedVector { private static readonly Vector2 Max = new(ushort.MaxValue); @@ -30,8 +26,14 @@ public partial struct Rg32(Vector2 vector) : IPixel, IPackedVector { } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Rg32(Vector2 vector) => this.PackedValue = Pack(vector); + /// - public uint PackedValue { get; set; } = Pack(vector); + public uint PackedValue { get; set; } /// /// Compares two objects for equality. @@ -90,21 +92,25 @@ public partial struct Rg32(Vector2 vector) : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rg32 FromVector4(Vector4 source) => new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rg32 FromAbgr32(Abgr32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rg32 FromArgb32(Argb32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rg32 FromBgr24(Bgr24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); + public static Rg32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rg32 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); + public static Rg32 FromBgr24(Bgr24 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rg32 FromAbgr32(Abgr32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); + public static Rg32 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G)); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index fc54accfd5..a4445bd716 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -15,37 +15,44 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 1] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The red component. -/// The green component. -/// The blue component. [StructLayout(LayoutKind.Explicit)] -[method: MethodImpl(MethodImplOptions.AggressiveInlining)] -public partial struct Rgb24(byte r, byte g, byte b) : IPixel +public partial struct Rgb24 : IPixel { /// /// The red component. /// [FieldOffset(0)] - public byte R = r; + public byte R; /// /// The green component. /// [FieldOffset(1)] - public byte G = g; + public byte G; /// /// The blue component. /// [FieldOffset(2)] - public byte B = b; + public byte B; private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Rgb24(byte r, byte g, byte b) + { + this.R = r; + this.G = g; + this.B = b; + } + /// /// Allows the implicit conversion of an instance of to a /// . @@ -77,6 +84,10 @@ public partial struct Rgb24(byte r, byte g, byte b) : IPixel [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgb24 left, Rgb24 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromRgb24(this); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); @@ -95,10 +106,6 @@ public partial struct Rgb24(byte r, byte g, byte b) : IPixel /// public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B); - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgb24 FromScaledVector4(Vector4 source) => FromVector4(source); @@ -117,19 +124,23 @@ public partial struct Rgb24(byte r, byte g, byte b) : IPixel /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); + public static Rgb24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + public static Rgb24 FromArgb32(Argb32 source) => new(source.R, source.G, source.B); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb24 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); + public static Rgb24 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb24 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B); + public static Rgb24 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index af901e3d28..d4f1cabb2c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -71,8 +71,7 @@ public partial struct Rgb48 : IPixel /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() - => new(ColorNumerics.From16BitTo8Bit(this.R), ColorNumerics.From16BitTo8Bit(this.G), ColorNumerics.From16BitTo8Bit(this.B)); + public readonly Rgba32 ToRgba32() => Rgba32.FromRgb48(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -104,11 +103,20 @@ public partial struct Rgb48 : IPixel return new((ushort)MathF.Round(source.X), (ushort)MathF.Round(source.Y), (ushort)MathF.Round(source.Z)); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromAbgr32(Abgr32 source) + => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgb48 FromArgb32(Argb32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgb48 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgb48 FromBgr24(Bgr24 source) @@ -119,10 +127,6 @@ public partial struct Rgb48 : IPixel public static Rgb48 FromBgra32(Bgra32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb48 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); - /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgb48 FromL8(L8 source) @@ -157,14 +161,13 @@ public partial struct Rgb48 : IPixel public static Rgb48 FromRgba32(Rgba32 source) => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); - /// + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb48 FromAbgr32(Abgr32 source) - => new(ColorNumerics.From8BitTo16Bit(source.R), ColorNumerics.From8BitTo16Bit(source.G), ColorNumerics.From8BitTo16Bit(source.B)); + public static Rgb48 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgb48 FromRgb48(Rgb48 source) => new(source.R, source.G, source.B); + public static Rgb48 FromRgba64(Rgba64 source) => new(source.R, source.G, source.B); /// public override readonly bool Equals(object? obj) => obj is Rgb48 rgb48 && this.Equals(rgb48); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 85ae045a09..0f7be17740 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -13,11 +13,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [0, 0, 0, 0] to [1, 1, 1, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct Rgba1010102(Vector4 vector) : IPixel, IPackedVector +public partial struct Rgba1010102 : IPixel, IPackedVector { private static readonly Vector4 Multiplier = new(1023F, 1023F, 1023F, 3F); @@ -33,8 +29,14 @@ public partial struct Rgba1010102(Vector4 vector) : IPixel, IPacked { } + /// + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Rgba1010102(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public uint PackedValue { get; set; } = Pack(vector); + public uint PackedValue { get; set; } /// /// Compares two objects for equality. @@ -58,6 +60,10 @@ public partial struct Rgba1010102(Vector4 vector) : IPixel, IPacked [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Rgba1010102 left, Rgba1010102 right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); @@ -88,6 +94,58 @@ public partial struct Rgba1010102(Vector4 vector) : IPixel, IPacked [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgba1010102 FromVector4(Vector4 source) => new() { PackedValue = Pack(source) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba1010102 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is Rgba1010102 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 83c376c9f6..8b5779a532 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -87,7 +87,9 @@ public partial struct Rgba32 : IPixel, IPackedVector /// The alpha component. [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(float r, float g, float b, float a = 1) - : this() => Pack(r, g, b, a); + : this(new Vector4(r, g, b, a)) + { + } /// /// Initializes a new instance of the struct. @@ -97,7 +99,9 @@ public partial struct Rgba32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public Rgba32(Vector3 vector) - : this() => Pack(vector); + : this(new Vector4(vector, 1f)) + { + } /// /// Initializes a new instance of the struct. @@ -296,19 +300,23 @@ public partial struct Rgba32 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + public static Rgba32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); + public static Rgba32 FromArgb32(Argb32 source) => new(source.R, source.G, source.B, source.A); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba32 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); + public static Rgba32 FromBgr24(Bgr24 source) => new(source.R, source.G, source.B); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba32 FromAbgr32(Abgr32 source) => new(source.R, source.G, source.B, source.A); + public static Rgba32 FromBgra32(Bgra32 source) => new(source.R, source.G, source.B, source.A); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -386,23 +394,6 @@ public partial struct Rgba32 : IPixel, IPackedVector /// public override readonly int GetHashCode() => this.Rgba.GetHashCode(); - /// - /// Packs the four floats into a color. - /// - /// The x-component - /// The y-component - /// The z-component - /// The w-component - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Rgba32 Pack(float x, float y, float z, float w) => Pack(new Vector4(x, y, z, w)); - - /// - /// Packs a into a uint. - /// - /// The vector containing the values to pack. - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Rgba32 Pack(Vector3 vector) => Pack(new Vector4(vector, 1f)); - /// /// Packs a into a color. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 5294064eb1..73629461b2 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -192,12 +192,7 @@ public partial struct Rgba64 : IPixel, IPackedVector /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgba32 ToRgba32() - => new( - ColorNumerics.From16BitTo8Bit(this.R), - ColorNumerics.From16BitTo8Bit(this.G), - ColorNumerics.From16BitTo8Bit(this.B), - ColorNumerics.From16BitTo8Bit(this.A)); + public readonly Rgba32 ToRgba32() => Rgba32.FromRgba64(this); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -225,21 +220,25 @@ public partial struct Rgba64 : IPixel, IPackedVector [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgba64 FromVector4(Vector4 source) => new(source); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Rgba64 FromAbgr32(Abgr32 source) => new(source); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Rgba64 FromArgb32(Argb32 source) => new(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba64 FromBgr24(Bgr24 source) => new(source); + public static Rgba64 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba64 FromBgra32(Bgra32 source) => new(source); + public static Rgba64 FromBgr24(Bgr24 source) => new(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Rgba64 FromAbgr32(Abgr32 source) => new(source); + public static Rgba64 FromBgra32(Bgra32 source) => new(source); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] @@ -286,68 +285,35 @@ public partial struct Rgba64 : IPixel, IPackedVector /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Bgra32 ToBgra32() - { - byte r = ColorNumerics.From16BitTo8Bit(this.R); - byte g = ColorNumerics.From16BitTo8Bit(this.G); - byte b = ColorNumerics.From16BitTo8Bit(this.B); - byte a = ColorNumerics.From16BitTo8Bit(this.A); - return new Bgra32(r, g, b, a); - } + public readonly Bgra32 ToBgra32() => Bgra32.FromRgba64(this); /// /// Convert to . /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Argb32 ToArgb32() - { - byte r = ColorNumerics.From16BitTo8Bit(this.R); - byte g = ColorNumerics.From16BitTo8Bit(this.G); - byte b = ColorNumerics.From16BitTo8Bit(this.B); - byte a = ColorNumerics.From16BitTo8Bit(this.A); - return new Argb32(r, g, b, a); - } + public readonly Argb32 ToArgb32() => Argb32.FromRgba64(this); /// /// Convert to . /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Abgr32 ToAbgr32() - { - byte r = ColorNumerics.From16BitTo8Bit(this.R); - byte g = ColorNumerics.From16BitTo8Bit(this.G); - byte b = ColorNumerics.From16BitTo8Bit(this.B); - byte a = ColorNumerics.From16BitTo8Bit(this.A); - return new Abgr32(r, g, b, a); - } + public readonly Abgr32 ToAbgr32() => Abgr32.FromRgba64(this); /// /// Convert to . /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Rgb24 ToRgb24() - { - byte r = ColorNumerics.From16BitTo8Bit(this.R); - byte g = ColorNumerics.From16BitTo8Bit(this.G); - byte b = ColorNumerics.From16BitTo8Bit(this.B); - return new Rgb24(r, g, b); - } + public readonly Rgb24 ToRgb24() => Rgb24.FromRgba64(this); /// /// Convert to . /// /// The . [MethodImpl(MethodImplOptions.AggressiveInlining)] - public readonly Bgr24 ToBgr24() - { - byte r = ColorNumerics.From16BitTo8Bit(this.R); - byte g = ColorNumerics.From16BitTo8Bit(this.G); - byte b = ColorNumerics.From16BitTo8Bit(this.B); - return new Bgr24(r, g, b); - } + public readonly Bgr24 ToBgr24() => Bgr24.FromRgba64(this); /// public override readonly bool Equals(object? obj) => obj is Rgba64 rgba64 && this.Equals(rgba64); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 0511f32794..60555ad95d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -19,41 +19,49 @@ namespace SixLabors.ImageSharp.PixelFormats; /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// -/// -/// Initializes a new instance of the struct. -/// -/// The red component. -/// The green component. -/// The blue component. -/// The alpha component. [StructLayout(LayoutKind.Sequential)] -[method: MethodImpl(MethodImplOptions.AggressiveInlining)] -public partial struct RgbaVector(float r, float g, float b, float a = 1) : IPixel +public partial struct RgbaVector : IPixel { /// /// Gets or sets the red component. /// - public float R = r; + public float R; /// /// Gets or sets the green component. /// - public float G = g; + public float G; /// /// Gets or sets the blue component. /// - public float B = b; + public float B; /// /// Gets or sets the alpha component. /// - public float A = a; + public float A; private const float MaxBytes = byte.MaxValue; private static readonly Vector4 Max = new(MaxBytes); private static readonly Vector4 Half = new(0.5F); + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public RgbaVector(float r, float g, float b, float a = 1) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + /// /// Compares two objects for equality. /// @@ -76,6 +84,10 @@ public partial struct RgbaVector(float r, float g, float b, float a = 1) : IPixe [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(RgbaVector left, RgbaVector right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() => this.ToVector4(); @@ -106,6 +118,58 @@ public partial struct RgbaVector(float r, float g, float b, float a = 1) : IPixe return new(source.X, source.Y, source.Z, source.W); } + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaVector FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Creates a new instance of the struct. /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index e2b652d1a8..043599c366 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-32767, -32767, 0, 1] to [32767, 32767, 0, 1] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// The vector containing the component values. -public partial struct Short2(Vector2 vector) : IPixel, IPackedVector +public partial struct Short2 : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -37,8 +33,14 @@ public partial struct Short2(Vector2 vector) : IPixel, IPackedVector + /// Initializes a new instance of the struct. + /// + /// The vector containing the component values. + public Short2(Vector2 vector) => this.PackedValue = Pack(vector); + /// - public uint PackedValue { get; set; } = Pack(vector); + public uint PackedValue { get; set; } /// /// Compares two objects for equality. @@ -62,6 +64,10 @@ public partial struct Short2(Vector2 vector) : IPixel, IPackedVector !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -99,6 +105,58 @@ public partial struct Short2(Vector2 vector) : IPixel, IPackedVector new() { PackedValue = Pack(new Vector2(source.X, source.Y)) }; + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short2 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// /// Expands the packed representation into a . /// The vector components are typically expanded in least to greatest significance order. diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index 18d7f22ec5..df43703cb7 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -12,11 +12,7 @@ namespace SixLabors.ImageSharp.PixelFormats; /// Ranges from [-37267, -37267, -37267, -37267] to [37267, 37267, 37267, 37267] in vector form. /// /// -/// -/// Initializes a new instance of the struct. -/// -/// A vector containing the initial values for the components. -public partial struct Short4(Vector4 vector) : IPixel, IPackedVector +public partial struct Short4 : IPixel, IPackedVector { // Largest two byte positive number 0xFFFF >> 1; private const float MaxPos = 0x7FFF; @@ -39,8 +35,14 @@ public partial struct Short4(Vector4 vector) : IPixel, IPackedVector + /// Initializes a new instance of the struct. + /// + /// A vector containing the initial values for the components. + public Short4(Vector4 vector) => this.PackedValue = Pack(vector); + /// - public ulong PackedValue { get; set; } = Pack(vector); + public ulong PackedValue { get; set; } /// /// Compares two objects for equality. @@ -64,6 +66,10 @@ public partial struct Short4(Vector4 vector) : IPixel, IPackedVector !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + /// [MethodImpl(MethodImplOptions.AggressiveInlining)] public readonly Vector4 ToScaledVector4() @@ -106,6 +112,58 @@ public partial struct Short4(Vector4 vector) : IPixel, IPackedVector new(source); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Short4 FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); + /// public override readonly bool Equals(object? obj) => obj is Short4 other && this.Equals(other); diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs index 7e84bd6392..712d43f760 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.cs @@ -14,20 +14,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Argb32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Argb32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Argb32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromArgb32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromArgb32(Unsafe.Add(ref sourceBase, i)); } } @@ -37,48 +34,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromArgb32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromArgb32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToArgb32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToArgb32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Argb32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Argb32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Argb32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Argb32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToArgb32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToArgb32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToArgb32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToArgb32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -86,20 +80,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Abgr32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Abgr32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Abgr32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromAbgr32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromAbgr32(Unsafe.Add(ref sourceBase, i)); } } @@ -109,48 +100,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromAbgr32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromAbgr32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromAbgr32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToAbgr32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Abgr32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Abgr32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Abgr32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Abgr32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToAbgr32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToAbgr32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToAbgr32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -158,20 +146,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgr24 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgr24 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgr24 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgr24(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgr24(Unsafe.Add(ref sourceBase, i)); } } @@ -181,48 +166,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgr24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgr24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgr24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgr24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgr24 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgr24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgr24 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgr24.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgr24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgr24Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgr24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgr24(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -230,20 +212,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgra32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgra32(Unsafe.Add(ref sourceBase, i)); } } @@ -253,48 +232,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgra32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgra32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgra32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgra32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgra32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgra32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgra32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -302,20 +278,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromL8(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromL8(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L8 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L8 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref L8 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromL8(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromL8(Unsafe.Add(ref sourceBase, i)); } } @@ -325,48 +298,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromL8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromL8Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromL8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromL8(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToL8(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToL8(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L8 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref L8 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L8 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = L8.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToL8Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToL8Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToL8(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToL8(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -374,20 +344,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromL16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromL16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref L16 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref L16 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref L16 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromL16(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromL16(Unsafe.Add(ref sourceBase, i)); } } @@ -397,48 +364,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromL16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromL16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromL16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromL16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToL16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToL16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref L16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref L16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref L16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = L16.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToL16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToL16Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToL16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToL16(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -446,20 +410,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromLa16(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromLa16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La16 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La16 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref La16 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromLa16(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromLa16(Unsafe.Add(ref sourceBase, i)); } } @@ -469,48 +430,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromLa16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromLa16Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromLa16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromLa16(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToLa16(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToLa16(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La16 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref La16 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref La16 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = La16.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToLa16Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToLa16Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToLa16(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToLa16(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -518,20 +476,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromLa32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromLa32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref La32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref La32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref La32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromLa32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromLa32(Unsafe.Add(ref sourceBase, i)); } } @@ -541,48 +496,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromLa32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromLa32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromLa32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromLa32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToLa32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToLa32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref La32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref La32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref La32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = La32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToLa32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToLa32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToLa32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToLa32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -590,20 +542,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb24 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb24 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb24 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgb24(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgb24(Unsafe.Add(ref sourceBase, i)); } } @@ -613,48 +562,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgb24Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgb24(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgb24(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgb24(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb24 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb24 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb24 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgb24.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb24Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgb24Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgb24(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb24(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -662,20 +608,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba32 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba32 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba32 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgba32(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgba32(Unsafe.Add(ref sourceBase, i)); } } @@ -685,48 +628,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgba32Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgba32(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgba32(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgba32(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba32 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba32 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba32 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgba32.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba32Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgba32Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgba32(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba32(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -734,20 +674,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgb48 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgb48 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgb48 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgb48(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgb48(Unsafe.Add(ref sourceBase, i)); } } @@ -757,48 +694,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgb48Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgb48(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgb48(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgb48(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgb48 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgb48 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgb48 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgb48.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgb48Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgb48Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgb48(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgb48(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -806,20 +740,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Rgba64 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Rgba64 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Rgba64 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromRgba64(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromRgba64(Unsafe.Add(ref sourceBase, i)); } } @@ -829,48 +760,45 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromRgba64Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromRgba64(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToRgba64(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToRgba64(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Rgba64 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Rgba64 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Rgba64 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Rgba64.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToRgba64Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToRgba64Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToRgba64(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToRgba64(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } /// @@ -878,20 +806,17 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destinationPixels) + /// The to the destination pixels. + public virtual void FromBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref Bgra5551 sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref Bgra5551 sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref Bgra5551 sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromBgra5551(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.FromBgra5551(Unsafe.Add(ref sourceBase, i)); } } @@ -901,47 +826,44 @@ public partial class PixelOperations /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBgra5551Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void FromBgra5551Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.FromBgra5551(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destinationPixels); + this.FromBgra5551(configuration, MemoryMarshal.Cast(sourceBytes).Slice(0, count), destination); } /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void ToBgra5551(Configuration configuration, ReadOnlySpan sourcePixels, Span destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void ToBgra5551(Configuration configuration, ReadOnlySpan source, Span destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref Bgra5551 destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref Bgra5551 destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref Bgra5551 dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = Bgra5551.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void ToBgra5551Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void ToBgra5551Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.ToBgra5551(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast(destBytes)); + this.ToBgra5551(configuration, source.Slice(0, count), MemoryMarshal.Cast(destination)); } } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt index 8ba3398e39..b2697cb4e4 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.Generated.tt @@ -20,20 +20,17 @@ /// /// A to configure internal operations. /// The source of data. - /// The to the destination pixels. - public virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destinationPixels) + /// The to the destination pixels. + public virtual void From<#=pixelType#>(Configuration configuration, ReadOnlySpan<<#=pixelType#>> source, Span destination) { - Guard.DestinationShouldNotBeTooShort(source, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref <#=pixelType#> sourceBaseRef = ref MemoryMarshal.GetReference(source); - ref TPixel destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref <#=pixelType#> sourceBase = ref MemoryMarshal.GetReference(source); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); for (nuint i = 0; i < (uint)source.Length; i++) { - ref <#=pixelType#> sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref TPixel dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.From<#=pixelType#>(sp); + Unsafe.Add(ref destinationBase, i) = TPixel.From<#=pixelType#>(Unsafe.Add(ref sourceBase, i)); } } @@ -43,12 +40,12 @@ /// /// A to configure internal operations. /// The to the source bytes. - /// The to the destination pixels. + /// The to the destination pixels. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destinationPixels, int count) + public void From<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourceBytes, Span destination, int count) { - this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destinationPixels); + this.From<#=pixelType#>(configuration, MemoryMarshal.Cast>(sourceBytes).Slice(0, count), destination); } <# @@ -58,39 +55,36 @@ { #> /// - /// Converts all pixels of the 'sourcePixels` span to a span of -s. + /// Converts all pixels of the 'source` span to a span of -s. /// /// A to configure internal operations - /// The span of source pixels - /// The destination span of data. - public virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan sourcePixels, Span<<#=pixelType#>> destinationPixels) + /// The span of source pixels + /// The destination span of data. + public virtual void To<#=pixelType#>(Configuration configuration, ReadOnlySpan source, Span<<#=pixelType#>> destination) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - ref TPixel sourceBaseRef = ref MemoryMarshal.GetReference(sourcePixels); - ref <#=pixelType#> destBaseRef = ref MemoryMarshal.GetReference(destinationPixels); + ref TPixel sourceBase = ref MemoryMarshal.GetReference(source); + ref <#=pixelType#> destinationBase = ref MemoryMarshal.GetReference(destination); - for (nuint i = 0; i < (uint)sourcePixels.Length; i++) + for (nuint i = 0; i < (uint)source.Length; i++) { - ref TPixel sp = ref Unsafe.Add(ref sourceBaseRef, i); - ref <#=pixelType#> dp = ref Unsafe.Add(ref destBaseRef, i); - - dp.FromScaledVector4(sp.ToScaledVector4()); + Unsafe.Add(ref destinationBase, i) = <#=pixelType#>.FromScaledVector4(Unsafe.Add(ref sourceBase, i).ToScaledVector4()); } } /// /// A helper for that expects a byte span as destination. - /// The layout of the data in 'destBytes' must be compatible with layout. + /// The layout of the data in 'destination' must be compatible with layout. /// /// A to configure internal operations - /// The to the source pixels. - /// The to the destination bytes. + /// The to the source pixels. + /// The to the destination bytes. /// The number of pixels to convert. [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan sourcePixels, Span destBytes, int count) + public void To<#=pixelType#>Bytes(Configuration configuration, ReadOnlySpan source, Span destination, int count) { - this.To<#=pixelType#>(configuration, sourcePixels.Slice(0, count), MemoryMarshal.Cast>(destBytes)); + this.To<#=pixelType#>(configuration, source.Slice(0, count), MemoryMarshal.Cast>(destination)); } <# } diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 4d3f9e22d4..174b3fae18 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -33,7 +33,7 @@ public partial class PixelOperations public PixelTypeInfo GetPixelTypeInfo() => TPixel.GetPixelTypeInfo(); /// - /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// The method is DESTRUCTIVE altering the contents of . /// /// @@ -42,21 +42,21 @@ public partial class PixelOperations /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. /// The to apply during the conversion public virtual void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { Guard.NotNull(configuration, nameof(configuration)); - Utils.Vector4Converters.Default.FromVector4(sourceVectors, destinationPixels, modifiers); + Utils.Vector4Converters.Default.FromVector4(sourceVectors, destination, modifiers); } /// - /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. + /// Bulk version of converting 'sourceVectors.Length' pixels into 'destinationColors'. /// The method is DESTRUCTIVE altering the contents of . /// /// @@ -65,77 +65,77 @@ public partial class PixelOperations /// /// A to configure internal operations /// The to the source vectors. - /// The to the destination colors. + /// The to the destination colors. public void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels) - => this.FromVector4Destructive(configuration, sourceVectors, destinationPixels, PixelConversionModifiers.None); + Span destination) + => this.FromVector4Destructive(configuration, sourceVectors, destination, PixelConversionModifiers.None); /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. + /// The to the source colors. /// The to the destination vectors. /// The to apply during the conversion public virtual void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors, PixelConversionModifiers modifiers) { Guard.NotNull(configuration, nameof(configuration)); - Utils.Vector4Converters.Default.ToVector4(sourcePixels, destinationVectors, modifiers); + Utils.Vector4Converters.Default.ToVector4(source, destinationVectors, modifiers); } /// /// Bulk version of converting 'sourceColors.Length' pixels into 'destinationVectors'. /// /// A to configure internal operations - /// The to the source colors. + /// The to the source colors. /// The to the destination vectors. public void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors) - => this.ToVector4(configuration, sourcePixels, destinationVectors, PixelConversionModifiers.None); + => this.ToVector4(configuration, source, destinationVectors, PixelConversionModifiers.None); /// - /// Bulk operation that copies the to in + /// Bulk operation that copies the to in /// format. /// /// The destination pixel type. /// A to configure internal operations. - /// The to the source pixels. - /// The to the destination pixels. + /// The to the source pixels. + /// The to the destination pixels. public virtual void From( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) where TSourcePixel : unmanaged, IPixel { const int sliceLength = 1024; - int numberOfSlices = sourcePixels.Length / sliceLength; + int numberOfSlices = source.Length / sliceLength; using IMemoryOwner tempVectors = configuration.MemoryAllocator.Allocate(sliceLength); Span vectorSpan = tempVectors.GetSpan(); for (int i = 0; i < numberOfSlices; i++) { int start = i * sliceLength; - ReadOnlySpan s = sourcePixels.Slice(start, sliceLength); - Span d = destinationPixels.Slice(start, sliceLength); + ReadOnlySpan s = source.Slice(start, sliceLength); + Span d = destination.Slice(start, sliceLength); PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); } int endOfCompleteSlices = numberOfSlices * sliceLength; - int remainder = sourcePixels.Length - endOfCompleteSlices; + int remainder = source.Length - endOfCompleteSlices; if (remainder > 0) { - ReadOnlySpan s = sourcePixels[endOfCompleteSlices..]; - Span d = destinationPixels[endOfCompleteSlices..]; + ReadOnlySpan s = source[endOfCompleteSlices..]; + Span d = destination[endOfCompleteSlices..]; vectorSpan = vectorSpan[..remainder]; PixelOperations.Instance.ToVector4(configuration, s, vectorSpan, PixelConversionModifiers.Scale); this.FromVector4Destructive(configuration, vectorSpan, d, PixelConversionModifiers.Scale); @@ -143,23 +143,23 @@ public partial class PixelOperations } /// - /// Bulk operation that copies the to in + /// Bulk operation that copies the to in /// format. /// /// The destination pixel type. /// A to configure internal operations. - /// The to the source pixels. - /// The to the destination pixels. + /// The to the source pixels. + /// The to the destination pixels. public virtual void To( Configuration configuration, - ReadOnlySpan sourcePixels, - Span destinationPixels) + ReadOnlySpan source, + Span destination) where TDestinationPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - PixelOperations.Instance.From(configuration, sourcePixels, destinationPixels); + PixelOperations.Instance.From(configuration, source, destination); } /// @@ -190,7 +190,7 @@ public partial class PixelOperations rgb24.R = Unsafe.Add(ref r, i); rgb24.G = Unsafe.Add(ref g, i); rgb24.B = Unsafe.Add(ref b, i); - Unsafe.Add(ref d, i).FromRgb24(rgb24); + Unsafe.Add(ref d, i) = TPixel.FromRgb24(rgb24); } } @@ -212,15 +212,13 @@ public partial class PixelOperations int count = source.Length; - Rgba32 rgba32 = default; - ref float r = ref MemoryMarshal.GetReference(redChannel); ref float g = ref MemoryMarshal.GetReference(greenChannel); ref float b = ref MemoryMarshal.GetReference(blueChannel); ref TPixel src = ref MemoryMarshal.GetReference(source); for (nuint i = 0; i < (uint)count; i++) { - Unsafe.Add(ref src, i).ToRgba32(ref rgba32); + Rgba32 rgba32 = Unsafe.Add(ref src, i).ToRgba32(); Unsafe.Add(ref r, i) = rgba32.R; Unsafe.Add(ref g, i) = rgba32.G; Unsafe.Add(ref b, i) = rgba32.B; diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs index 4d07a8a9b6..d7cac15309 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.Default.cs @@ -21,139 +21,139 @@ internal static partial class Vector4Converters { [MethodImpl(InliningOptions.ShortMethod)] public static void FromVector4( - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - UnsafeFromVector4(sourceVectors, destPixels, modifiers); + UnsafeFromVector4(source, destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] public static void ToVector4( - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - UnsafeToVector4(sourcePixels, destVectors, modifiers); + UnsafeToVector4(source, destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] public static void UnsafeFromVector4( - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { - ApplyBackwardConversionModifiers(sourceVectors, modifiers); + ApplyBackwardConversionModifiers(source, modifiers); if (modifiers.IsDefined(PixelConversionModifiers.Scale)) { - UnsafeFromScaledVector4Core(sourceVectors, destPixels); + UnsafeFromScaledVector4Core(source, destination); } else { - UnsafeFromVector4Core(sourceVectors, destPixels); + UnsafeFromVector4Core(source, destination); } } [MethodImpl(InliningOptions.ShortMethod)] public static void UnsafeToVector4( - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { if (modifiers.IsDefined(PixelConversionModifiers.Scale)) { - UnsafeToScaledVector4Core(sourcePixels, destVectors); + UnsafeToScaledVector4Core(source, destination); } else { - UnsafeToVector4Core(sourcePixels, destVectors); + UnsafeToVector4Core(source, destination); } - ApplyForwardConversionModifiers(destVectors, modifiers); + ApplyForwardConversionModifiers(destination, modifiers); } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeFromVector4Core( - ReadOnlySpan sourceVectors, - Span destPixels) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref Vector4 sourceStart = ref MemoryMarshal.GetReference(sourceVectors); - ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceVectors.Length); - ref TPixel destRef = ref MemoryMarshal.GetReference(destPixels); + ref Vector4 sourceStart = ref MemoryMarshal.GetReference(source); + ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef.FromVector4(sourceStart); + destinationBase = TPixel.FromVector4(sourceStart); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeToVector4Core( - ReadOnlySpan sourcePixels, - Span destVectors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref TPixel sourceStart = ref MemoryMarshal.GetReference(sourcePixels); - ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourcePixels.Length); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destVectors); + ref TPixel sourceStart = ref MemoryMarshal.GetReference(source); + ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref Vector4 destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef = sourceStart.ToVector4(); + destinationBase = sourceStart.ToVector4(); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeFromScaledVector4Core( - ReadOnlySpan sourceVectors, - Span destinationColors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref Vector4 sourceStart = ref MemoryMarshal.GetReference(sourceVectors); - ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceVectors.Length); - ref TPixel destRef = ref MemoryMarshal.GetReference(destinationColors); + ref Vector4 sourceStart = ref MemoryMarshal.GetReference(source); + ref Vector4 sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref TPixel destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef.FromScaledVector4(sourceStart); + destinationBase = TPixel.FromScaledVector4(sourceStart); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } [MethodImpl(InliningOptions.ShortMethod)] private static void UnsafeToScaledVector4Core( - ReadOnlySpan sourceColors, - Span destinationVectors) + ReadOnlySpan source, + Span destination) where TPixel : unmanaged, IPixel { - ref TPixel sourceStart = ref MemoryMarshal.GetReference(sourceColors); - ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)sourceColors.Length); - ref Vector4 destRef = ref MemoryMarshal.GetReference(destinationVectors); + ref TPixel sourceStart = ref MemoryMarshal.GetReference(source); + ref TPixel sourceEnd = ref Unsafe.Add(ref sourceStart, (uint)source.Length); + ref Vector4 destinationBase = ref MemoryMarshal.GetReference(destination); while (Unsafe.IsAddressLessThan(ref sourceStart, ref sourceEnd)) { - destRef = sourceStart.ToScaledVector4(); + destinationBase = sourceStart.ToScaledVector4(); sourceStart = ref Unsafe.Add(ref sourceStart, 1); - destRef = ref Unsafe.Add(ref destRef, 1); + destinationBase = ref Unsafe.Add(ref destinationBase, 1); } } } diff --git a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs index cbf893915c..ae891f3507 100644 --- a/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Convolution/EdgeDetectorCompassProcessor{TPixel}.cs @@ -125,10 +125,7 @@ internal class EdgeDetectorCompassProcessor : ImageProcessor // Grab the max components of the two pixels ref TPixel currentPassPixel = ref Unsafe.Add(ref passPixelsBase, x); ref TPixel currentTargetPixel = ref Unsafe.Add(ref targetPixelsBase, x); - - var pixelValue = Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4()); - - currentTargetPixel.FromVector4(pixelValue); + currentTargetPixel = TPixel.FromVector4(Vector4.Max(currentPassPixel.ToVector4(), currentTargetPixel.ToVector4())); } } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs index f1d7fbd6f3..3c0ebb7074 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/ErrorDither.cs @@ -203,7 +203,7 @@ public readonly partial struct ErrorDither : IDither, IEquatable, I Vector4 result = pixel.ToVector4(); result += error * coefficient; - pixel.FromVector4(result); + pixel = TPixel.FromVector4(result); } } diff --git a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs index 1a02e7a221..d1f46c7441 100644 --- a/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs +++ b/src/ImageSharp/Processing/Processors/Dithering/OrderedDither.cs @@ -181,8 +181,7 @@ public readonly partial struct OrderedDither : IDither, IEquatable { - Unsafe.SkipInit(out Rgba32 rgba); - source.ToRgba32(ref rgba); + Rgba32 rgba = source.ToRgba32(); Unsafe.SkipInit(out Rgba32 attempt); float factor = spread * this.thresholdMatrix[y % this.modulusY, x % this.modulusX] * scale; @@ -192,10 +191,7 @@ public readonly partial struct OrderedDither : IDither, IEquatable diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs index 0baa87a611..78085eaab5 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationProcessor{TPixel}.cs @@ -64,11 +64,11 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz int luminanceLevels = this.LuminanceLevels; // The image is split up into tiles. For each tile the cumulative distribution function will be calculated. - using (var cdfData = new CdfTileData(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) + using (CdfTileData cdfData = new(this.Configuration, sourceWidth, sourceHeight, this.Tiles, this.Tiles, tileWidth, tileHeight, luminanceLevels)) { cdfData.CalculateLookupTables(source, this); - var tileYStartPositions = new List<(int Y, int CdfY)>(); + List<(int Y, int CdfY)> tileYStartPositions = []; int cdfY = 0; int yStart = halfTileHeight; for (int tile = 0; tile < tileCount - 1; tile++) @@ -78,7 +78,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz yStart += tileHeight; } - var operation = new RowIntervalOperation(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source.PixelBuffer); + RowIntervalOperation operation = new(cdfData, tileYStartPositions, tileWidth, tileHeight, tileCount, halfTileWidth, luminanceLevels, source.PixelBuffer); ParallelRowIterator.IterateRowIntervals( this.Configuration, new Rectangle(0, 0, sourceWidth, tileYStartPositions.Count), @@ -145,7 +145,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = cdfData.RemapGreyValue(cdfX, cdfY, GetLuminance(pixel, luminanceLevels)); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } } } @@ -191,7 +191,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = InterpolateBetweenTwoTiles(pixel, cdfData, cdfX, cdfY, cdfX, cdfY + 1, tileY, tileHeight, luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); } tileY++; @@ -243,7 +243,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz { ref TPixel pixel = ref rowSpan[dx]; float luminanceEqualized = InterpolateBetweenTwoTiles(pixel, cdfData, cdfX, cdfY, cdfX + 1, cdfY, tileX, tileWidth, luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); tileX++; } } @@ -404,10 +404,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz { for (int index = rows.Min; index < rows.Max; index++) { - (int Y, int CdfY) tileYStartPosition = this.tileYStartPositions[index]; - int y = tileYStartPosition.Y; - int cdfYY = tileYStartPosition.CdfY; - + (int y, int cdfY) = this.tileYStartPositions[index]; int cdfX = 0; int x = this.halfTileWidth; for (int tile = 0; tile < this.tileCount - 1; tile++) @@ -430,12 +427,12 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz tileX, tileY, cdfX, - cdfYY, + cdfY, this.tileWidth, this.tileHeight, this.luminanceLevels); - pixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); + pixel = TPixel.FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, pixel.ToVector4().W)); tileX++; } @@ -494,7 +491,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz this.pixelsInTile = tileWidth * tileHeight; // Calculate the start positions and rent buffers. - this.tileYStartPositions = new List<(int Y, int CdfY)>(); + this.tileYStartPositions = []; int cdfY = 0; for (int y = 0; y < sourceHeight; y += tileHeight) { @@ -505,7 +502,7 @@ internal class AdaptiveHistogramEqualizationProcessor : HistogramEqualiz public void CalculateLookupTables(ImageFrame source, HistogramEqualizationProcessor processor) { - var operation = new RowIntervalOperation( + RowIntervalOperation operation = new( processor, this.memoryAllocator, this.cdfMinBuffer2D, diff --git a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs index d2bec0b49b..93144653e3 100644 --- a/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Normalization/AdaptiveHistogramEqualizationSlidingWindowProcessor{TPixel}.cs @@ -383,7 +383,7 @@ internal class AdaptiveHistogramEqualizationSlidingWindowProcessor : His // Map the current pixel to the new equalized value. int luminance = GetLuminance(this.source[x, y], this.processor.LuminanceLevels); float luminanceEqualized = Unsafe.Add(ref cdfBase, (uint)luminance) / numberOfPixelsMinusCdfMin; - this.targetPixels[x, y].FromVector4(new Vector4(luminanceEqualized, luminanceEqualized, luminanceEqualized, this.source[x, y].ToVector4().W)); + this.targetPixels[x, y] = TPixel.FromVector4(new(luminanceEqualized, luminanceEqualized, luminanceEqualized, this.source[x, y].ToVector4().W)); // Remove top most row from the histogram, mirroring rows which exceeds the borders. if (this.useFastPath) diff --git a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs index 72148374aa..4fd37d479d 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/EuclideanPixelMap{TPixel}.cs @@ -55,8 +55,7 @@ internal sealed class EuclideanPixelMap : IDisposable PixelOperations.Instance.ToRgba32(configuration, this.Palette.Span, this.rgbaPalette); this.transparentIndex = transparentIndex; - Unsafe.SkipInit(out this.transparentMatch); - this.transparentMatch.FromRgba32(default); + this.transparentMatch = TPixel.FromRgba32(default); } /// @@ -76,8 +75,7 @@ internal sealed class EuclideanPixelMap : IDisposable public int GetClosestColor(TPixel color, out TPixel match) { ref TPixel paletteRef = ref MemoryMarshal.GetReference(this.Palette.Span); - Unsafe.SkipInit(out Rgba32 rgba); - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); // Check if the color is in the lookup table if (!this.cache.TryGetValue(rgba, out short index)) diff --git a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs index 039417578e..8b39b74579 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/OctreeQuantizer{TPixel}.cs @@ -277,8 +277,7 @@ public struct OctreeQuantizer : IQuantizer [MethodImpl(InliningOptions.ShortMethod)] public int GetPaletteIndex(TPixel color) { - Unsafe.SkipInit(out Rgba32 rgba); - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); return this.root.GetPaletteIndex(ref rgba, 0); } @@ -476,9 +475,7 @@ public struct OctreeQuantizer : IQuantizer Vector3.Zero, new Vector3(255)); - Unsafe.SkipInit(out TPixel pixel); - pixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z, byte.MaxValue)); - palette[index] = pixel; + palette[index] = TPixel.FromRgba32(new Rgba32((byte)vector.X, (byte)vector.Y, (byte)vector.Z)); // Consume the next palette index this.paletteIndex = index++; diff --git a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs index e13975b56e..ba2ab825ad 100644 --- a/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs +++ b/src/ImageSharp/Processing/Processors/Quantization/WuQuantizer{TPixel}.cs @@ -142,8 +142,7 @@ internal struct WuQuantizer : IQuantizer if (moment.Weight > 0) { - ref TPixel color = ref paletteSpan[k]; - color.FromScaledVector4(moment.Normalize()); + paletteSpan[k] = TPixel.FromScaledVector4(moment.Normalize()); } } @@ -178,8 +177,7 @@ internal struct WuQuantizer : IQuantizer return (byte)this.pixelMap!.GetClosestColor(color, out match); } - Rgba32 rgba = default; - color.ToRgba32(ref rgba); + Rgba32 rgba = color.ToRgba32(); const int shift = 8 - IndexBits; int r = rgba.R >> shift; @@ -549,7 +547,7 @@ internal struct WuQuantizer : IQuantizer /// The first set. /// The second set. /// Returns a value indicating whether the box has been split. - private bool Cut(ref Box set1, ref Box set2) + private readonly bool Cut(ref Box set1, ref Box set2) { ReadOnlySpan momentSpan = this.momentsOwner.GetSpan(); Moment whole = Volume(ref set1, momentSpan); diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs index bd938c9da9..6cae208538 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromRgba32Bytes.cs @@ -49,23 +49,17 @@ public abstract class FromRgba32Bytes for (int i = 0; i < this.Count; i++) { int i4 = i * 4; - var c = default(TPixel); - c.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); - d[i] = c; + d[i] = TPixel.FromRgba32(new Rgba32(s[i4], s[i4 + 1], s[i4 + 2], s[i4 + 3])); } } [Benchmark(Baseline = true)] public void CommonBulk() - { - new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + => new PixelOperations().FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); [Benchmark] public void OptimizedBulk() - { - PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); - } + => PixelOperations.Instance.FromRgba32Bytes(this.configuration, this.source.GetSpan(), this.destination.GetSpan(), this.Count); } public class FromRgba32Bytes_ToRgba32 : FromRgba32Bytes diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs index d70c37ccba..ecd16b9578 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs @@ -49,21 +49,17 @@ public abstract class FromVector4 ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan()); for (nuint i = 0; i < (uint)this.Count; i++) { - Unsafe.Add(ref d, i).FromVector4(Unsafe.Add(ref s, i)); + Unsafe.Add(ref d, i) = TPixel.FromVector4(Unsafe.Add(ref s, i)); } } [Benchmark(Baseline = true)] public void PixelOperations_Base() - { - new PixelOperations().FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); - } + => new PixelOperations().FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); [Benchmark] public void PixelOperations_Specialized() - { - PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); - } + => PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); } public class FromVector4Rgba32 : FromVector4 diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs b/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs index 6d3f8f9528..19ab780c01 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToRgba32Bytes.cs @@ -47,8 +47,7 @@ public abstract class ToRgba32Bytes { TPixel c = s[i]; int i4 = i * 4; - Rgba32 rgba = default; - c.ToRgba32(ref rgba); + Rgba32 rgba = c.ToRgba32(); d[i4] = rgba.R; d[i4 + 1] = rgba.G; d[i4 + 2] = rgba.B; diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs index 0ee507832a..a8c6a021ae 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Argb32.cs @@ -12,8 +12,7 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public class PixelConversion_Rgba32_To_Argb32 { private Rgba32[] source; - - private Argb32[] dest; + private Argb32[] destination; [Params(64)] public int Count { get; set; } @@ -22,19 +21,19 @@ public class PixelConversion_Rgba32_To_Argb32 public void Setup() { this.source = new Rgba32[this.Count]; - this.dest = new Argb32[this.Count]; + this.destination = new Argb32[this.Count]; } [Benchmark(Baseline = true)] public void Default() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i++) { Rgba32 s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = Argb32.FromRgba32(s); } } @@ -48,21 +47,18 @@ public class PixelConversion_Rgba32_To_Argb32 for (nuint i = 0; i < (uint)source.Length; i++) { Rgba32 s = Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = TPixel.FromRgba32(s); } } [Benchmark] - public void Default_Generic() - { - Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Generic() => Default_GenericImpl(this.source.AsSpan(), this.destination.AsSpan()); [Benchmark] public void Default_Group2() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i += 2) { @@ -70,8 +66,8 @@ public class PixelConversion_Rgba32_To_Argb32 Rgba32 s1 = Unsafe.Add(ref s0, 1); ref Argb32 d0 = ref Unsafe.Add(ref dBase, i); - d0.FromRgba32(s0); - Unsafe.Add(ref d0, 1).FromRgba32(s1); + d0 = Argb32.FromRgba32(s0); + Unsafe.Add(ref d0, 1) = Argb32.FromRgba32(s1); } } @@ -79,7 +75,7 @@ public class PixelConversion_Rgba32_To_Argb32 public void Default_Group4() { ref Rgba32 sBase = ref this.source[0]; - ref Argb32 dBase = ref this.dest[0]; + ref Argb32 dBase = ref this.destination[0]; for (nuint i = 0; i < (uint)this.Count; i += 4) { @@ -92,10 +88,10 @@ public class PixelConversion_Rgba32_To_Argb32 ref Argb32 d1 = ref Unsafe.Add(ref d0, 1); ref Argb32 d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = Argb32.FromRgba32(s0); + d1 = Argb32.FromRgba32(s1); + d2 = Argb32.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = Argb32.FromRgba32(s3); } } @@ -103,7 +99,7 @@ public class PixelConversion_Rgba32_To_Argb32 public void BitOps() { ref uint sBase = ref Unsafe.As(ref this.source[0]); - ref uint dBase = ref Unsafe.As(ref this.dest[0]); + ref uint dBase = ref Unsafe.As(ref this.destination[0]); for (nuint i = 0; i < (uint)this.Count; i++) { @@ -116,7 +112,7 @@ public class PixelConversion_Rgba32_To_Argb32 public void BitOps_GroupAsULong() { ref ulong sBase = ref Unsafe.As(ref this.source[0]); - ref ulong dBase = ref Unsafe.As(ref this.dest[0]); + ref ulong dBase = ref Unsafe.As(ref this.destination[0]); for (nuint i = 0; i < (uint)this.Count / 2; i++) { @@ -134,10 +130,6 @@ public class PixelConversion_Rgba32_To_Argb32 public static class FromRgba32 { - /// - /// Converts a packed to . - /// - /// The argb value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { @@ -146,10 +138,6 @@ public class PixelConversion_Rgba32_To_Argb32 return (packedRgba << 8) | (packedRgba >> 24); } - /// - /// Converts a packed to . - /// - /// The bgra value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToBgra32(uint packedRgba) { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs index 499f3483dc..f4fb9e4204 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_Rgba32_To_Bgra32.cs @@ -55,7 +55,7 @@ public class PixelConversion_Rgba32_To_Bgra32 for (nuint i = 0; i < (uint)this.Count; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = Bgra32.FromRgba32(s); } } @@ -69,15 +69,12 @@ public class PixelConversion_Rgba32_To_Bgra32 for (nuint i = 0; i < (uint)source.Length; i++) { ref Rgba32 s = ref Unsafe.Add(ref sBase, i); - Unsafe.Add(ref dBase, i).FromRgba32(s); + Unsafe.Add(ref dBase, i) = TPixel.FromRgba32(s); } } [Benchmark] - public void Default_Generic() - { - Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Generic() => Default_GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); [Benchmark] public void Default_Group2() @@ -91,8 +88,8 @@ public class PixelConversion_Rgba32_To_Bgra32 Rgba32 s1 = Unsafe.Add(ref s0, 1); ref Bgra32 d0 = ref Unsafe.Add(ref dBase, i); - d0.FromRgba32(s0); - Unsafe.Add(ref d0, 1).FromRgba32(s1); + d0 = Bgra32.FromRgba32(s0); + Unsafe.Add(ref d0, 1) = Bgra32.FromRgba32(s1); } } @@ -113,10 +110,10 @@ public class PixelConversion_Rgba32_To_Bgra32 ref Bgra32 d1 = ref Unsafe.Add(ref d0, 1); ref Bgra32 d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = Bgra32.FromRgba32(s0); + d1 = Bgra32.FromRgba32(s1); + d2 = Bgra32.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = Bgra32.FromRgba32(s3); } } @@ -138,18 +135,15 @@ public class PixelConversion_Rgba32_To_Bgra32 ref TPixel d1 = ref Unsafe.Add(ref d0, 1); ref TPixel d2 = ref Unsafe.Add(ref d1, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - Unsafe.Add(ref d2, 1).FromRgba32(s3); + d0 = TPixel.FromRgba32(s0); + d1 = TPixel.FromRgba32(s1); + d2 = TPixel.FromRgba32(s2); + Unsafe.Add(ref d2, 1) = TPixel.FromRgba32(s3); } } // [Benchmark] - public void Default_Group4_Generic() - { - Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); - } + public void Default_Group4_Generic() => Group4GenericImpl(this.source.AsSpan(), this.dest.AsSpan()); // [Benchmark] public void Default_Group8() @@ -178,15 +172,15 @@ public class PixelConversion_Rgba32_To_Bgra32 ref Bgra32 d5 = ref Unsafe.Add(ref d4, 1); ref Bgra32 d6 = ref Unsafe.Add(ref d5, 1); - d0.FromRgba32(s0); - d1.FromRgba32(s1); - d2.FromRgba32(s2); - d3.FromRgba32(s3); + d0 = Bgra32.FromRgba32(s0); + d1 = Bgra32.FromRgba32(s1); + d2 = Bgra32.FromRgba32(s2); + d3 = Bgra32.FromRgba32(s3); - d4.FromRgba32(s4); - d5.FromRgba32(s5); - d6.FromRgba32(s6); - Unsafe.Add(ref d6, 1).FromRgba32(s7); + d4 = Bgra32.FromRgba32(s4); + d5 = Bgra32.FromRgba32(s5); + d6 = Bgra32.FromRgba32(s6); + Unsafe.Add(ref d6, 1) = Bgra32.FromRgba32(s7); } } @@ -352,10 +346,6 @@ public class PixelConversion_Rgba32_To_Bgra32 public static class FromRgba32 { - /// - /// Converts a packed to . - /// - /// The argb value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToArgb32(uint packedRgba) { @@ -364,10 +354,6 @@ public class PixelConversion_Rgba32_To_Bgra32 return (packedRgba << 8) | (packedRgba >> 24); } - /// - /// Converts a packed to . - /// - /// The bgra value. [MethodImpl(InliningOptions.ShortMethod)] public static uint ToBgra32(uint packedRgba) { diff --git a/tests/ImageSharp.Tests/Color/RgbaDouble.cs b/tests/ImageSharp.Tests/Color/RgbaDouble.cs index fdd736930d..bb86729416 100644 --- a/tests/ImageSharp.Tests/Color/RgbaDouble.cs +++ b/tests/ImageSharp.Tests/Color/RgbaDouble.cs @@ -19,41 +19,49 @@ namespace SixLabors.ImageSharp.Tests; /// This struct is fully mutable. This is done (against the guidelines) for the sake of performance, /// as it avoids the need to create new values for modification operations. /// -/// -/// Initializes a new instance of the struct. -/// -/// The red component. -/// The green component. -/// The blue component. -/// The alpha component. [StructLayout(LayoutKind.Sequential)] -[method: MethodImpl(InliningOptions.ShortMethod)] -public partial struct RgbaDouble(double r, double g, double b, double a = 1) : IPixel +public struct RgbaDouble : IPixel { /// /// Gets or sets the red component. /// - public double R = r; + public double R; /// /// Gets or sets the green component. /// - public double G = g; + public double G; /// /// Gets or sets the blue component. /// - public double B = b; + public double B; /// /// Gets or sets the alpha component. /// - public double A = a; + public double A; private const float MaxBytes = byte.MaxValue; private static readonly Vector4 Max = new(MaxBytes); private static readonly Vector4 Half = new(0.5F); + /// + /// Initializes a new instance of the struct. + /// + /// The red component. + /// The green component. + /// The blue component. + /// The alpha component. + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public RgbaDouble(double r, double g, double b, double a = 1) + { + this.R = r; + this.G = g; + this.B = b; + this.A = a; + } + /// /// Compares two objects for equality. /// @@ -76,6 +84,18 @@ public partial struct RgbaDouble(double r, double g, double b, double a = 1) : I [MethodImpl(InliningOptions.ShortMethod)] public static bool operator !=(RgbaDouble left, RgbaDouble right) => !left.Equals(right); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToScaledVector4() => this.ToVector4(); + + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new((float)this.R, (float)this.G, (float)this.B, (float)this.A); + /// public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( @@ -87,83 +107,68 @@ public partial struct RgbaDouble(double r, double g, double b, double a = 1) : I public readonly PixelOperations CreatePixelOperations() => new(); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromScaledVector4(Vector4 vector) => this.FromVector4(vector); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromScaledVector4(Vector4 source) => FromVector4(source); /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToScaledVector4() => this.ToVector4(); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromVector4(Vector4 vector) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromVector4(Vector4 source) { - vector = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); - this.R = vector.X; - this.G = vector.Y; - this.B = vector.Z; - this.A = vector.W; + source = Numerics.Clamp(source, Vector4.Zero, Vector4.One); + return new(source.X, source.Y, source.Z, source.W); } - /// - [MethodImpl(InliningOptions.ShortMethod)] - public readonly Vector4 ToVector4() => new((float)this.R, (float)this.G, (float)this.B, (float)this.A); - - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromArgb32(Argb32 source) => this.FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgr24(Bgr24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromAbgr32(Abgr32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra32(Bgra32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromArgb32(Argb32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromAbgr32(Abgr32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgra5551(Bgra5551 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromBgra5551(Bgra5551 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgr24(Bgr24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL8(L8 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromBgra32(Bgra32 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromL16(L16 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromL8(L8 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa16(La16 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromL16(L16 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromLa32(La32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromLa16(La16 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb24(Rgb24 source) => this.FromScaledVector4(source.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromLa32(La32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba32(Rgba32 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgb24(Rgb24 source) => FromScaledVector4(source.ToScaledVector4()); /// - [MethodImpl(InliningOptions.ShortMethod)] - public void ToRgba32(ref Rgba32 dest) => dest.FromScaledVector4(this.ToScaledVector4()); + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgba32(Rgba32 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgb48(Rgb48 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgb48(Rgb48 source) => FromScaledVector4(source.ToScaledVector4()); - /// - [MethodImpl(InliningOptions.ShortMethod)] - public void FromRgba64(Rgba64 source) => this.FromScaledVector4(source.ToScaledVector4()); + /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static RgbaDouble FromRgba64(Rgba64 source) => FromScaledVector4(source.ToScaledVector4()); /// public override readonly bool Equals(object obj) => obj is RgbaDouble other && this.Equals(other); diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 3e8e171645..c81eaea633 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -26,7 +26,7 @@ public partial class SimdUtilsTests [InlineData(5.3, 536.4, 4.5, 8.1)] public void PseudoRound(float x, float y, float z, float w) { - var v = new Vector4(x, y, z, w); + Vector4 v = new(x, y, z, w); Vector4 actual = v.PseudoRound(); @@ -57,7 +57,7 @@ public partial class SimdUtilsTests { float[] data = new float[Vector.Count]; - var rnd = new Random(seed); + Random rnd = new(seed); for (int i = 0; i < Vector.Count; i++) { @@ -185,10 +185,10 @@ public partial class SimdUtilsTests short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); float[] fData = sData.Select(u => (float)u).ToArray(); - var source = new Vector(sData); + Vector source = new(sData); - var expected1 = new Vector(fData, 0); - var expected2 = new Vector(fData, n); + Vector expected1 = new(fData, 0); + Vector expected2 = new(fData, n); // Act: SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); @@ -262,7 +262,7 @@ public partial class SimdUtilsTests byte[] g = Enumerable.Range(100, 32).Select(x => (byte)x).ToArray(); byte[] b = Enumerable.Range(200, 32).Select(x => (byte)x).ToArray(); const int padding = 4; - var d = new Rgb24[32 + padding]; + Rgb24[] d = new Rgb24[32 + padding]; ReadOnlySpan rr = r.AsSpan(); ReadOnlySpan gg = g.AsSpan(); @@ -296,7 +296,7 @@ public partial class SimdUtilsTests byte[] g = Enumerable.Range(100, 32).Select(x => (byte)x).ToArray(); byte[] b = Enumerable.Range(200, 32).Select(x => (byte)x).ToArray(); - var d = new Rgba32[32]; + Rgba32[] d = new Rgba32[32]; ReadOnlySpan rr = r.AsSpan(); ReadOnlySpan gg = g.AsSpan(); @@ -322,18 +322,18 @@ public partial class SimdUtilsTests internal static void TestPackFromRgbPlanes(int count, Action packMethod) where TPixel : unmanaged, IPixel { - var rnd = new Random(42); + Random rnd = new(42); byte[] r = rnd.GenerateRandomByteArray(count); byte[] g = rnd.GenerateRandomByteArray(count); byte[] b = rnd.GenerateRandomByteArray(count); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromRgb24(new Rgb24(r[i], g[i], b[i])); + expected[i] = TPixel.FromRgb24(new Rgb24(r[i], g[i], b[i])); } - var actual = new TPixel[count + 3]; // padding for Rgb24 AVX2 + TPixel[] actual = new TPixel[count + 3]; // padding for Rgb24 AVX2 packMethod(r, g, b, actual); Assert.True(expected.AsSpan().SequenceEqual(actual.AsSpan()[..count])); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs index 80365b4724..65d0a01ffe 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.ComponentData.cs @@ -42,7 +42,7 @@ internal static partial class LibJpegTools public int QuantizationTableIndex => throw new NotSupportedException(); - public Buffer2D SpectralBlocks { get; private set; } + public Buffer2D SpectralBlocks { get; } public short MinVal { get; private set; } = short.MaxValue; @@ -102,7 +102,7 @@ internal static partial class LibJpegTools public static ComponentData Load(JpegComponent c, int index) { - var result = new ComponentData( + ComponentData result = new( c.WidthInBlocks, c.HeightInBlocks, index); @@ -113,7 +113,7 @@ internal static partial class LibJpegTools public Image CreateGrayScaleImage() { - var result = new Image(this.WidthInBlocks * 8, this.HeightInBlocks * 8); + Image result = new(this.WidthInBlocks * 8, this.HeightInBlocks * 8); for (int by = 0; by < this.HeightInBlocks; by++) { @@ -136,9 +136,8 @@ internal static partial class LibJpegTools { float val = this.GetBlockValue(block, x, y); - var v = new Vector4(val, val, val, 1); - Rgba32 color = default; - color.FromVector4(v); + Vector4 v = new(val, val, val, 1); + Rgba32 color = Rgba32.FromVector4(v); int yy = (by * 8) + y; int xx = (bx * 8) + x; @@ -198,7 +197,7 @@ internal static partial class LibJpegTools return false; } - if (object.ReferenceEquals(this, obj)) + if (ReferenceEquals(this, obj)) { return true; } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs index a4bb6b7bfc..9eec547a36 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/Utils/LibJpegTools.SpectralData.cs @@ -14,11 +14,11 @@ internal static partial class LibJpegTools /// public class SpectralData : IEquatable { - public int ComponentCount { get; private set; } + public int ComponentCount { get; } - public LibJpegTools.ComponentData[] Components { get; private set; } + public ComponentData[] Components { get; } - internal SpectralData(LibJpegTools.ComponentData[] components) + internal SpectralData(ComponentData[] components) { this.ComponentCount = components.Length; this.Components = components; @@ -31,16 +31,16 @@ internal static partial class LibJpegTools return null; } - LibJpegTools.ComponentData c0 = this.Components[0]; - LibJpegTools.ComponentData c1 = this.Components[1]; - LibJpegTools.ComponentData c2 = this.Components[2]; + ComponentData c0 = this.Components[0]; + ComponentData c1 = this.Components[1]; + ComponentData c2 = this.Components[2]; if (c0.Size != c1.Size || c1.Size != c2.Size) { return null; } - var result = new Image(c0.WidthInBlocks * 8, c0.HeightInBlocks * 8); + Image result = new(c0.WidthInBlocks * 8, c0.HeightInBlocks * 8); for (int by = 0; by < c0.HeightInBlocks; by++) { @@ -55,18 +55,14 @@ internal static partial class LibJpegTools internal void WriteToImage(int bx, int by, Image image) { - LibJpegTools.ComponentData c0 = this.Components[0]; - LibJpegTools.ComponentData c1 = this.Components[1]; - LibJpegTools.ComponentData c2 = this.Components[2]; + ComponentData c0 = this.Components[0]; + ComponentData c1 = this.Components[1]; + ComponentData c2 = this.Components[2]; Block8x8 block0 = c0.SpectralBlocks[bx, by]; Block8x8 block1 = c1.SpectralBlocks[bx, by]; Block8x8 block2 = c2.SpectralBlocks[bx, by]; - float d0 = c0.MaxVal - c0.MinVal; - float d1 = c1.MaxVal - c1.MinVal; - float d2 = c2.MaxVal - c2.MinVal; - for (int y = 0; y < 8; y++) { for (int x = 0; x < 8; x++) @@ -75,9 +71,8 @@ internal static partial class LibJpegTools float val1 = c0.GetBlockValue(block1, x, y); float val2 = c0.GetBlockValue(block2, x, y); - var v = new Vector4(val0, val1, val2, 1); - Rgba32 color = default; - color.FromVector4(v); + Vector4 v = new(val0, val1, val2, 1); + Rgba32 color = Rgba32.FromVector4(v); int yy = (by * 8) + y; int xx = (bx * 8) + x; @@ -105,8 +100,8 @@ internal static partial class LibJpegTools for (int i = 0; i < this.ComponentCount; i++) { - LibJpegTools.ComponentData a = this.Components[i]; - LibJpegTools.ComponentData b = other.Components[i]; + ComponentData a = this.Components[i]; + ComponentData b = other.Components[i]; if (!a.Equals(b)) { return false; @@ -116,10 +111,7 @@ internal static partial class LibJpegTools return true; } - public override bool Equals(object obj) - { - return obj is SpectralData other && this.Equals(other); - } + public override bool Equals(object obj) => obj is SpectralData other && this.Equals(other); public override int GetHashCode() { @@ -139,9 +131,6 @@ internal static partial class LibJpegTools return left.Equals(right); } - public static bool operator !=(SpectralData left, SpectralData right) - { - return !(left == right); - } + public static bool operator !=(SpectralData left, SpectralData right) => !(left == right); } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 825becb36a..0fdd496308 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -406,7 +406,7 @@ public partial class PngEncoderTests for (int x = 0; x < image.Width; x++) { - rowSpan[x].FromRgba32(rgba32); + rowSpan[x] = Rgba32.FromRgba32(rgba32); } } }); diff --git a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs index f0961de6bb..b4279b0454 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs @@ -80,7 +80,7 @@ public class PredictorEncoderTests // Convert image pixels to bgra array. byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Peak)); - using var image = Image.Load(imgBytes); + using Image image = Image.Load(imgBytes); uint[] bgra = ToBgra(image); const int colorTransformBits = 3; @@ -110,7 +110,7 @@ public class PredictorEncoderTests // Convert image pixels to bgra array. byte[] imgBytes = File.ReadAllBytes(TestImageFullPath(TestImages.Webp.Lossy.BikeSmall)); - using var image = Image.Load(imgBytes); + using Image image = Image.Load(imgBytes); uint[] bgra = ToBgra(image); const int colorTransformBits = 4; @@ -149,10 +149,8 @@ public class PredictorEncoderTests private static Bgra32 ToBgra32(TPixel color) where TPixel : unmanaged, IPixel { - Rgba32 rgba = default; - color.ToRgba32(ref rgba); - var bgra = new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A); - return bgra; + Rgba32 rgba = color.ToRgba32(); + return new Bgra32(rgba.R, rgba.G, rgba.B, rgba.A); } private static string TestImageFullPath(string path) diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 51f1ef7c67..23a3913fae 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -10,8 +10,8 @@ public class Issue594 { // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void NormalizedByte4() + [Fact] // (Skip = "Skipped because of issue #594")] + public void NormalizedByte4Test() { // Test PackedValue Assert.Equal(0x0U, new NormalizedByte4(Vector4.Zero).PackedValue); @@ -33,68 +33,27 @@ public class Issue594 Assert.Equal(0, scaled.W); // Test FromScaledVector4. - var pixel = default(NormalizedByte4); - pixel.FromScaledVector4(scaled); + NormalizedByte4 pixel = NormalizedByte4.FromScaledVector4(scaled); Assert.Equal(0x81818181, pixel.PackedValue); // Test Ordering - float x = 0.1f; - float y = -0.3f; - float z = 0.5f; - float w = -0.7f; - Assert.Equal(0xA740DA0D, new NormalizedByte4(x, y, z, w).PackedValue); - var n = default(NormalizedByte4); - n.FromRgba32(new Rgba32(141, 90, 192, 39)); + const float x = 0.1f; + const float y = -0.3f; + const float z = 0.5f; + const float w = -0.7f; + + pixel = new(x, y, z, w); + Assert.Equal(0xA740DA0D, pixel.PackedValue); + NormalizedByte4 n = NormalizedByte4.FromRgba32(pixel.ToRgba32()); Assert.Equal(0xA740DA0D, n.PackedValue); Assert.Equal(958796544U, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new NormalizedByte4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(141, 90, 192)); - - // new NormalizedByte4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); - - // new NormalizedByte4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(141, 90, 192)); - - // new NormalizedByte4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - - // new NormalizedByte4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - - // http://community.monogame.net/t/normalizedbyte4-texture2d-gives-different-results-from-xna/8012/8 - // var r = default(NormalizedByte4); - // r.FromRgba32(new Rgba32(9, 115, 202, 127)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r.PackedValue = 0xff4af389; - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r = default(NormalizedByte4); - // r.FromArgb32(new Argb32(9, 115, 202, 127)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(9, 115, 202, 127)); - - // r = default(NormalizedByte4); - // r.FromBgra32(new Bgra32(9, 115, 202, 127)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void NormalizedShort4() + [Fact] //(Skip = "Skipped because of issue #594")] + public void NormalizedShort4Test() { // Test PackedValue Assert.Equal(0x0UL, new NormalizedShort4(Vector4.Zero).PackedValue); @@ -116,59 +75,22 @@ public class Issue594 Assert.Equal(1, scaled.W); // Test FromScaledVector4. - var pixel = default(NormalizedShort4); - pixel.FromScaledVector4(scaled); + NormalizedShort4 pixel = NormalizedShort4.FromScaledVector4(scaled); Assert.Equal(0x7FFF7FFF7FFF7FFFUL, pixel.PackedValue); // Test Ordering - float x = 0.1f; - float y = -0.3f; - float z = 0.5f; - float w = -0.7f; + const float x = 0.1f; + const float y = -0.3f; + const float z = 0.5f; + const float w = -0.7f; Assert.Equal(0xa6674000d99a0ccd, new NormalizedShort4(x, y, z, w).PackedValue); Assert.Equal(4150390751449251866UL, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new NormalizedShort4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(141, 90, 192)); - - // new NormalizedShort4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(141, 90, 192, 39)); // this assert fails in Release build on linux (#594) - - // new NormalizedShort4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(141, 90, 192)); - - // new NormalizedShort4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(141, 90, 192, 39)); - - // new NormalizedShort4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(141, 90, 192, 39)); - - // var r = default(NormalizedShort4); - // r.FromRgba32(new Rgba32(9, 115, 202, 127)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(9, 115, 202, 127)); - - // r = default(NormalizedShort4); - // r.FromBgra32(new Bgra32(9, 115, 202, 127)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(9, 115, 202, 127)); - - // r = default(NormalizedShort4); - // r.FromArgb32(new Argb32(9, 115, 202, 127)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(9, 115, 202, 127)); } // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact(Skip = "Skipped because of issue #594")] - public void Short4() + [Fact] // (Skip = "Skipped because of issue #594")] + public void Short4Test() { // Test the limits. Assert.Equal(0x0UL, new Short4(Vector4.Zero).PackedValue); @@ -192,8 +114,7 @@ public class Issue594 Assert.Equal(1, scaled.W); // Test FromScaledVector4. - var pixel = default(Short4); - pixel.FromScaledVector4(scaled); + Short4 pixel = Short4.FromScaledVector4(scaled); Assert.Equal(0x7FFF7FFF7FFF7FFFUL, pixel.PackedValue); // Test clamping. @@ -212,52 +133,11 @@ public class Issue594 z = 29623; w = 193; Assert.Equal(0x00c173b7316d2d1bUL, new Short4(x, y, z, w).PackedValue); - - // var rgb = default(Rgb24); - // var rgba = default(Rgba32); - // var bgr = default(Bgr24); - // var bgra = default(Bgra32); - // var argb = default(Argb32); - - // new Short4(x, y, z, w).ToRgb24(ref rgb); - // Assert.Equal(rgb, new Rgb24(172, 177, 243)); // this assert fails in Release build on linux (#594) - - // new Short4(x, y, z, w).ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(172, 177, 243, 128)); - - // new Short4(x, y, z, w).ToBgr24(ref bgr); - // Assert.Equal(bgr, new Bgr24(172, 177, 243)); - - // new Short4(x, y, z, w).ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(172, 177, 243, 128)); - - // new Short4(x, y, z, w).ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(172, 177, 243, 128)); - - // var r = default(Short4); - // r.FromRgba32(new Rgba32(20, 38, 0, 255)); - // r.ToRgba32(ref rgba); - // Assert.Equal(rgba, new Rgba32(20, 38, 0, 255)); - - // r = default(Short4); - // r.FromBgra32(new Bgra32(20, 38, 0, 255)); - // r.ToBgra32(ref bgra); - // Assert.Equal(bgra, new Bgra32(20, 38, 0, 255)); - - // r = default(Short4); - // r.FromArgb32(new Argb32(20, 38, 0, 255)); - // r.ToArgb32(ref argb); - // Assert.Equal(argb, new Argb32(20, 38, 0, 255)); } + // TODO: Use tolerant comparer. // Comparison helpers with small tolerance to allow for floating point rounding during computations. - public static bool Equal(float a, float b) - { - return Math.Abs(a - b) < 1e-5; - } + public static bool Equal(float a, float b) => Math.Abs(a - b) < 1e-5; - public static bool Equal(Vector4 a, Vector4 b) - { - return Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W); - } + public static bool Equal(Vector4 a, Vector4 b) => Equal(a.X, b.X) && Equal(a.Y, b.Y) && Equal(a.Z, b.Z) && Equal(a.W, b.W); } diff --git a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs index b7a86d488c..4b4e84b4b3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/A8Tests.cs @@ -41,12 +41,11 @@ public class A8Tests public void A8_FromScaledVector4() { // Arrange - A8 alpha = default; - int expected = 128; + const int expected = 128; Vector4 scaled = new A8(.5F).ToScaledVector4(); // Act - alpha.FromScaledVector4(scaled); + A8 alpha = A8.FromScaledVector4(scaled); byte actual = alpha.PackedValue; // Assert @@ -91,8 +90,7 @@ public class A8Tests A8 input = new(128); Rgba32 expected = new(0, 0, 0, 128); - Rgba32 actual = default; - input.ToRgba32(ref actual); + Rgba32 actual = input.ToRgba32(); Assert.Equal(expected, actual); } @@ -100,11 +98,10 @@ public class A8Tests public void A8_FromBgra5551() { // arrange - A8 alpha = default; - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - alpha.FromBgra5551(new Bgra5551(0.0f, 0.0f, 0.0f, 1.0f)); + A8 alpha = A8.FromBgra5551(new Bgra5551(0.0f, 0.0f, 0.0f, 1.0f)); // assert Assert.Equal(expected, alpha.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs index 7f584b1bf5..98fdce5dbd 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Abgr32Tests.cs @@ -96,8 +96,7 @@ public class Abgr32Tests [Fact] public void FromRgba32() { - Abgr32 abgr = default; - abgr.FromRgba32(new Rgba32(1, 2, 3, 4)); + Abgr32 abgr = Abgr32.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, abgr.R); Assert.Equal(2, abgr.G); @@ -114,8 +113,7 @@ public class Abgr32Tests [Fact] public void FromVector4() { - Abgr32 c = default; - c.FromVector4(Vec(1, 2, 3, 4)); + Abgr32 c = Abgr32.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); @@ -135,11 +133,10 @@ public class Abgr32Tests public void Abgr32_FromBgra5551() { // arrange - Abgr32 abgr = default; - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - abgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Abgr32 abgr = Abgr32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, abgr.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs index 42b940845d..bcaf9265a3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Argb32Tests.cs @@ -18,8 +18,8 @@ public class Argb32Tests { Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); Argb32 color2 = new(new Vector4(0.0f)); - Argb32 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - Argb32 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); + Argb32 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + Argb32 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -32,9 +32,9 @@ public class Argb32Tests public void AreNotEqual() { Argb32 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - Argb32 color2 = new(new Vector4(1.0f)); - Argb32 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - Argb32 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + Argb32 color2 = new(new Vector4(1f)); + Argb32 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Argb32 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -111,11 +111,10 @@ public class Argb32Tests { // arrange Vector4 scaled = new Argb32(Vector4.One).ToScaledVector4(); - Argb32 pixel = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - pixel.FromScaledVector4(scaled); + Argb32 pixel = Argb32.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -126,11 +125,10 @@ public class Argb32Tests public void Argb32_FromBgra5551() { // arrange - Argb32 argb = default; - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - argb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Argb32 argb = Argb32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, argb.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs index 239e883960..362e20bbae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr24Tests.cs @@ -80,8 +80,7 @@ public class Bgr24Tests [Fact] public void FromRgba32() { - Bgr24 rgb = default; - rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); + Bgr24 rgb = Bgr24.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -97,8 +96,7 @@ public class Bgr24Tests [Fact] public void FromVector4() { - Bgr24 rgb = default; - rgb.FromVector4(Vec(1, 2, 3, 4)); + Bgr24 rgb = Bgr24.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -116,11 +114,8 @@ public class Bgr24Tests [Fact] public void Bgr24_FromBgra5551() { - // arrange - Bgr24 bgr = default; - // act - bgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr24 bgr = Bgr24.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(255, bgr.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs index 2ad4f4cf7c..3c4a104233 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgr565Tests.cs @@ -84,11 +84,10 @@ public class Bgr565Tests { // arrange Vector4 scaled = new Bgr565(Vector3.One).ToScaledVector4(); - int expected = 0xFFFF; - Bgr565 pixel = default; + const int expected = 0xFFFF; // act - pixel.FromScaledVector4(scaled); + Bgr565 pixel = Bgr565.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -99,11 +98,10 @@ public class Bgr565Tests public void Bgr565_FromBgra5551() { // arrange - Bgr565 bgr = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr = Bgr565.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -113,14 +111,12 @@ public class Bgr565Tests public void Bgr565_FromArgb32() { // arrange - Bgr565 bgr1 = default; - Bgr565 bgr2 = default; - ushort expected1 = ushort.MaxValue; - ushort expected2 = ushort.MaxValue; + const ushort expected1 = ushort.MaxValue; + const ushort expected2 = ushort.MaxValue; // act - bgr1.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 1.0f)); - bgr2.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 0.0f)); + Bgr565 bgr1 = Bgr565.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr2 = Bgr565.FromArgb32(new Argb32(1.0f, 1.0f, 1.0f, 0.0f)); // assert Assert.Equal(expected1, bgr1.PackedValue); @@ -131,14 +127,12 @@ public class Bgr565Tests public void Bgr565_FromRgba32() { // arrange - Bgr565 bgr1 = default; - Bgr565 bgr2 = default; - ushort expected1 = ushort.MaxValue; - ushort expected2 = ushort.MaxValue; + const ushort expected1 = ushort.MaxValue; + const ushort expected2 = ushort.MaxValue; // act - bgr1.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 1.0f)); - bgr2.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 0.0f)); + Bgr565 bgr1 = Bgr565.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 1.0f)); + Bgr565 bgr2 = Bgr565.FromRgba32(new Rgba32(1.0f, 1.0f, 1.0f, 0.0f)); // assert Assert.Equal(expected1, bgr1.PackedValue); @@ -149,12 +143,11 @@ public class Bgr565Tests public void Bgr565_ToRgba32() { // arrange - Bgr565 bgra = new(Vector3.One); + Bgr565 pixel = new(Vector3.One); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -163,11 +156,10 @@ public class Bgr565Tests public void Bgra565_FromRgb48() { // arrange - Bgr565 bgr = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgr.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, bgr.PackedValue); @@ -177,11 +169,10 @@ public class Bgr565Tests public void Bgra565_FromRgba64() { // arrange - Bgr565 bgr = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgr.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, bgr.PackedValue); @@ -191,11 +182,10 @@ public class Bgr565Tests public void Bgr565_FromBgr24() { // arrange - Bgr565 bgr = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgr565 bgr = Bgr565.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -205,11 +195,10 @@ public class Bgr565Tests public void Bgr565_FromRgb24() { // arrange - Bgr565 bgr = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgr565 bgr = Bgr565.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -219,11 +208,10 @@ public class Bgr565Tests public void Bgr565_FromGrey8() { // arrange - Bgr565 bgr = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromL8(new L8(byte.MaxValue)); + Bgr565 bgr = Bgr565.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); @@ -233,11 +221,10 @@ public class Bgr565Tests public void Bgr565_FromGrey16() { // arrange - Bgr565 bgr = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgr.FromL16(new L16(ushort.MaxValue)); + Bgr565 bgr = Bgr565.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expected, bgr.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs index df8d1199f2..277975896e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra32Tests.cs @@ -96,8 +96,7 @@ public class Bgra32Tests [Fact] public void FromRgba32() { - Bgra32 bgra = default; - bgra.FromRgba32(new Rgba32(1, 2, 3, 4)); + Bgra32 bgra = Bgra32.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, bgra.R); Assert.Equal(2, bgra.G); @@ -114,8 +113,7 @@ public class Bgra32Tests [Fact] public void FromVector4() { - Bgra32 c = default; - c.FromVector4(Vec(1, 2, 3, 4)); + Bgra32 c = Bgra32.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, c.R); Assert.Equal(2, c.G); @@ -135,11 +133,10 @@ public class Bgra32Tests public void Bgra32_FromBgra5551() { // arrange - Bgra32 bgra = default; - uint expected = uint.MaxValue; + const uint expected = uint.MaxValue; // act - bgra.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgra32 bgra = Bgra32.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, bgra.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs index ef587f3011..5d20b5cf12 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra4444Tests.cs @@ -67,10 +67,10 @@ public class Bgra4444Tests public void Bgra4444_ToScaledVector4() { // arrange - Bgra4444 bgra = new(Vector4.One); + Bgra4444 pixel = new(Vector4.One); // act - Vector4 actual = bgra.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -83,12 +83,11 @@ public class Bgra4444Tests public void Bgra4444_ToRgba32() { // arrange - Bgra4444 bgra = new(Vector4.One); + Bgra4444 pixel = new(Vector4.One); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -98,12 +97,11 @@ public class Bgra4444Tests { // arrange Vector4 scaled = new Bgra4444(Vector4.One).ToScaledVector4(); - int expected = 0xFFFF; - Bgra4444 bgra = default; + const int expected = 0xFFFF; // act - bgra.FromScaledVector4(scaled); - ushort actual = bgra.PackedValue; + Bgra4444 pixel = Bgra4444.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -113,42 +111,38 @@ public class Bgra4444Tests public void Bgra4444_FromBgra5551() { // arrange - Bgra4444 bgra = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - bgra.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Bgra4444 pixel = Bgra4444.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, bgra.PackedValue); + Assert.Equal(expected, pixel.PackedValue); } [Fact] public void Bgra4444_FromArgb32() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromArgb32(new Argb32(255, 255, 255, 255)); + Bgra4444 pixel = Bgra4444.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgba32() { // arrange - Bgra4444 bgra1 = default; - Bgra4444 bgra2 = default; - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFF0F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFF0F; // act - bgra1.FromRgba32(new Rgba32(255, 255, 255, 255)); - bgra2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Bgra4444 bgra1 = Bgra4444.FromRgba32(new Rgba32(255, 255, 255, 255)); + Bgra4444 bgra2 = Bgra4444.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -159,84 +153,78 @@ public class Bgra4444Tests public void Bgra4444_FromRgb48() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgba64() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromGrey16() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL16(new L16(ushort.MaxValue)); + Bgra4444 pixel = Bgra4444.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromGrey8() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL8(new L8(byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromBgr24() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra4444_FromRgb24() { // arrange - Bgra4444 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra4444 pixel = Bgra4444.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs index 5140cfda1a..38f809e49f 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Bgra5551Tests.cs @@ -18,8 +18,8 @@ public class Bgra5551Tests { Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); Bgra5551 color2 = new(new Vector4(0.0f)); - Bgra5551 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - Bgra5551 color4 = new(1.0f, 0.0f, 0.0f, 1.0f); + Bgra5551 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Bgra5551 color4 = new(1f, 0.0f, 0.0f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -32,9 +32,9 @@ public class Bgra5551Tests public void AreNotEqual() { Bgra5551 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - Bgra5551 color2 = new(new Vector4(1.0f)); - Bgra5551 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - Bgra5551 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + Bgra5551 color2 = new(new Vector4(1f)); + Bgra5551 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Bgra5551 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -43,10 +43,10 @@ public class Bgra5551Tests [Fact] public void Bgra5551_PackedValue() { - float x = 0x1a; - float y = 0x16; - float z = 0xd; - float w = 0x1; + const float x = 0x1a; + const float y = 0x16; + const float z = 0xd; + const float w = 0x1; Assert.Equal(0xeacd, new Bgra5551(x / 0x1f, y / 0x1f, z / 0x1f, w).PackedValue); Assert.Equal(3088, new Bgra5551(0.1f, -0.3f, 0.5f, -0.7f).PackedValue); @@ -72,10 +72,10 @@ public class Bgra5551Tests public void Bgra5551_ToScaledVector4() { // arrange - Bgra5551 bgra = new(Vector4.One); + Bgra5551 pixel = new(Vector4.One); // act - Vector4 actual = bgra.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -88,12 +88,11 @@ public class Bgra5551Tests public void Bgra5551_ToRgba32() { // arrange - Bgra5551 bgra = new(Vector4.One); + Bgra5551 pixel = new(Vector4.One); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - bgra.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -103,11 +102,10 @@ public class Bgra5551Tests { // arrange Vector4 scaled = new Bgra5551(Vector4.One).ToScaledVector4(); - int expected = 0xFFFF; - Bgra5551 pixel = default; + const int expected = 0xFFFF; // act - pixel.FromScaledVector4(scaled); + Bgra5551 pixel = Bgra5551.FromScaledVector4(scaled); ushort actual = pixel.PackedValue; // assert @@ -118,13 +116,11 @@ public class Bgra5551Tests public void Bgra5551_FromBgra5551() { // arrange - Bgra5551 bgra = default; - Bgra5551 actual = default; - Bgra5551 expected = new(1.0f, 0.0f, 1.0f, 1.0f); + Bgra5551 expected = new(1f, 0.0f, 1f, 1f); // act - bgra.FromBgra5551(expected); - actual.FromBgra5551(bgra); + Bgra5551 pixel = Bgra5551.FromBgra5551(expected); + Bgra5551 actual = Bgra5551.FromBgra5551(pixel); // assert Assert.Equal(expected, actual); @@ -134,14 +130,12 @@ public class Bgra5551Tests public void Bgra5551_FromRgba32() { // arrange - Bgra5551 bgra1 = default; - Bgra5551 bgra2 = default; - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFC1F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFC1F; // act - bgra1.FromRgba32(new Rgba32(255, 255, 255, 255)); - bgra2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Bgra5551 bgra1 = Bgra5551.FromRgba32(new Rgba32(255, 255, 255, 255)); + Bgra5551 bgra2 = Bgra5551.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -152,14 +146,12 @@ public class Bgra5551Tests public void Bgra5551_FromBgra32() { // arrange - Bgra5551 bgra1 = default; - Bgra5551 bgra2 = default; - ushort expectedPackedValue1 = ushort.MaxValue; - ushort expectedPackedValue2 = 0xFC1F; + const ushort expectedPackedValue1 = ushort.MaxValue; + const ushort expectedPackedValue2 = 0xFC1F; // act - bgra1.FromBgra32(new Bgra32(255, 255, 255, 255)); - bgra2.FromBgra32(new Bgra32(255, 0, 255, 255)); + Bgra5551 bgra1 = Bgra5551.FromBgra32(new Bgra32(255, 255, 255, 255)); + Bgra5551 bgra2 = Bgra5551.FromBgra32(new Bgra32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, bgra1.PackedValue); @@ -170,99 +162,91 @@ public class Bgra5551Tests public void Bgra5551_FromArgb32() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromArgb32(new Argb32(255, 255, 255, 255)); + Bgra5551 pixel = Bgra5551.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgb48() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgba64() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromGrey16() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL16(new L16(ushort.MaxValue)); + Bgra5551 pixel = Bgra5551.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromGrey8() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromL8(new L8(byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromBgr24() { // arrange - Bgra5551 bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Bgra5551_FromRgb24() { // arrange - Bgra5551 - bgra = default; - ushort expectedPackedValue = ushort.MaxValue; + const ushort expectedPackedValue = ushort.MaxValue; // act - bgra.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Bgra5551 pixel = Bgra5551.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, bgra.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs index a61318db7c..e73d646408 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Byte4Tests.cs @@ -16,10 +16,10 @@ public class Byte4Tests [Fact] public void AreEqual() { - Byte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - Byte4 color2 = new(new Vector4(0.0f)); - Byte4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - Byte4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); + Byte4 color1 = new(0f, 0f, 0f, 0f); + Byte4 color2 = new(new Vector4(0f)); + Byte4 color3 = new(new Vector4(1f, 0f, 1f, 1f)); + Byte4 color4 = new(1f, 0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -31,10 +31,10 @@ public class Byte4Tests [Fact] public void AreNotEqual() { - Byte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - Byte4 color2 = new(new Vector4(1.0f)); - Byte4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - Byte4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + Byte4 color1 = new(0f, 0f, 0f, 0f); + Byte4 color2 = new(new Vector4(1f)); + Byte4 color3 = new(new Vector4(1f, 0f, 0f, 1f)); + Byte4 color4 = new(1f, 1f, 0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -64,10 +64,10 @@ public class Byte4Tests public void Byte4_ToScaledVector4() { // arrange - Byte4 byte4 = new(Vector4.One * 255); + Byte4 pixel = new(Vector4.One * 255); // act - Vector4 actual = byte4.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(1, actual.X); @@ -80,12 +80,11 @@ public class Byte4Tests public void Byte4_ToRgba32() { // arrange - Byte4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + Byte4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -95,11 +94,10 @@ public class Byte4Tests { // arrange Vector4 scaled = new Byte4(Vector4.One * 255).ToScaledVector4(); - Byte4 pixel = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - pixel.FromScaledVector4(scaled); + Byte4 pixel = Byte4.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -110,126 +108,117 @@ public class Byte4Tests public void Byte4_FromArgb32() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + Byte4 pixel = Byte4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromBgr24() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Byte4 pixel = Byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromGrey8() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromL8(new L8(byte.MaxValue)); + Byte4 pixel = Byte4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromGrey16() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromL16(new L16(ushort.MaxValue)); + Byte4 pixel = Byte4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromRgb24() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Byte4 pixel = Byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromBgra5551() { // arrange - Byte4 byte4 = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - byte4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Byte4 pixel = Byte4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, byte4.PackedValue); + Assert.Equal(expected, pixel.PackedValue); } [Fact] public void Byte4_FromRgba32() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue1 = uint.MaxValue; + const uint expectedPackedValue1 = uint.MaxValue; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + Byte4 pixel = Byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expectedPackedValue1, byte4.PackedValue); + Assert.Equal(expectedPackedValue1, pixel.PackedValue); } [Fact] public void Byte4_FromRgb48() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Byte4 pixel = Byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] public void Byte4_FromRgba64() { // arrange - Byte4 byte4 = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Byte4 pixel = Byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expectedPackedValue, byte4.PackedValue); + Assert.Equal(expectedPackedValue, pixel.PackedValue); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs index 3e84da7231..9366c51c98 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfSingleTests.cs @@ -26,11 +26,11 @@ public class HalfSingleTests public void HalfSingle_ToVector4() { // arrange - HalfSingle halfSingle = new(0.5f); + HalfSingle pixel = new(0.5f); Vector4 expected = new(0.5f, 0, 0, 1); // act - Vector4 actual = halfSingle.ToVector4(); + Vector4 actual = pixel.ToVector4(); // assert Assert.Equal(expected, actual); @@ -40,10 +40,10 @@ public class HalfSingleTests public void HalfSingle_ToScaledVector4() { // arrange - HalfSingle halfSingle = new(-1F); + HalfSingle pixel = new(-1F); // act - Vector4 actual = halfSingle.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -57,12 +57,11 @@ public class HalfSingleTests { // arrange Vector4 scaled = new HalfSingle(-1F).ToScaledVector4(); - int expected = 48128; - HalfSingle halfSingle = default; + const int expected = 48128; // act - halfSingle.FromScaledVector4(scaled); - ushort actual = halfSingle.PackedValue; + HalfSingle pixel = HalfSingle.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs index 04e3ee35fe..c5a89df1e9 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector2Tests.cs @@ -48,11 +48,10 @@ public class HalfVector2Tests { // arrange Vector4 scaled = new HalfVector2(Vector2.One).ToScaledVector4(); - uint expected = 1006648320u; - HalfVector2 halfVector = default; + const uint expected = 1006648320u; // act - halfVector.FromScaledVector4(scaled); + HalfVector2 halfVector = HalfVector2.FromScaledVector4(scaled); uint actual = halfVector.PackedValue; // assert @@ -76,14 +75,11 @@ public class HalfVector2Tests [Fact] public void HalfVector2_FromBgra5551() { - // arrange - HalfVector2 halfVector2 = default; - // act - halfVector2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + HalfVector2 pixel = HalfVector2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Vector4 actual = halfVector2.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); Assert.Equal(1F, actual.X); Assert.Equal(1F, actual.Y); Assert.Equal(0, actual.Z); diff --git a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs index e8420ddd0d..16c78a23d3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/HalfVector4Tests.cs @@ -39,10 +39,10 @@ public class HalfVector4Tests public void HalfVector4_ToScaledVector4() { // arrange - HalfVector4 halfVector4 = new(-Vector4.One); + HalfVector4 pixel = new(-Vector4.One); // act - Vector4 actual = halfVector4.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -55,13 +55,12 @@ public class HalfVector4Tests public void HalfVector4_FromScaledVector4() { // arrange - HalfVector4 halfVector4 = default; Vector4 scaled = new HalfVector4(-Vector4.One).ToScaledVector4(); - ulong expected = 13547034390470638592uL; + const ulong expected = 13547034390470638592uL; // act - halfVector4.FromScaledVector4(scaled); - ulong actual = halfVector4.PackedValue; + HalfVector4 pixel = HalfVector4.FromScaledVector4(scaled); + ulong actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -71,14 +70,13 @@ public class HalfVector4Tests public void HalfVector4_FromBgra5551() { // arrange - HalfVector4 halfVector4 = default; Vector4 expected = Vector4.One; // act - halfVector4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + HalfVector4 pixel = HalfVector4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, halfVector4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs index 447433dabe..2ddf1accb6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L16Tests.cs @@ -40,13 +40,12 @@ public class L16Tests public void L16_FromScaledVector4() { // Arrange - L16 gray = default; const ushort expected = 32767; Vector4 scaled = new L16(expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromScaledVector4(scaled); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -59,10 +58,10 @@ public class L16Tests public void L16_ToScaledVector4(ushort input) { // Arrange - L16 gray = new(input); + L16 pixel = new(input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float vectorInput = input / 65535F; @@ -76,13 +75,12 @@ public class L16Tests public void L16_FromVector4() { // Arrange - L16 gray = default; const ushort expected = 32767; Vector4 vector = new L16(expected).ToVector4(); // Act - gray.FromVector4(vector); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromVector4(vector); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -95,10 +93,10 @@ public class L16Tests public void L16_ToVector4(ushort input) { // Arrange - L16 gray = new(input); + L16 pixel = new(input); // Act - Vector4 actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -112,14 +110,13 @@ public class L16Tests public void L16_FromRgba32() { // Arrange - L16 gray = default; const byte rgb = 128; ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - ushort actual = gray.PackedValue; + L16 pixel = L16.FromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -133,11 +130,10 @@ public class L16Tests { // Arrange ushort expected = ColorNumerics.From16BitTo8Bit(input); - L16 gray = new(input); + L16 pixel = new(input); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(expected, actual.R); @@ -150,14 +146,13 @@ public class L16Tests public void L16_FromBgra5551() { // arrange - L16 gray = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - gray.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + L16 pixel = L16.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert - Assert.Equal(expected, gray.PackedValue); + Assert.Equal(expected, pixel.PackedValue); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs index 81f4d61fba..40c746cf21 100644 --- a/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/L8Tests.cs @@ -44,13 +44,12 @@ public class L8Tests public void L8_FromScaledVector4() { // Arrange - L8 gray = default; const byte expected = 128; Vector4 scaled = new L8(expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - byte actual = gray.PackedValue; + L8 pixel = L8.FromScaledVector4(scaled); + byte actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -61,10 +60,10 @@ public class L8Tests public void L8_ToScaledVector4(byte input) { // Arrange - L8 gray = new(input); + L8 pixel = new(input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float scaledInput = input / 255F; @@ -79,12 +78,11 @@ public class L8Tests public void L8_FromVector4(byte luminance) { // Arrange - L8 gray = default; Vector4 vector = new L8(luminance).ToVector4(); // Act - gray.FromVector4(vector); - byte actual = gray.PackedValue; + L8 pixel = L8.FromVector4(vector); + byte actual = pixel.PackedValue; // Assert Assert.Equal(luminance, actual); @@ -95,10 +93,10 @@ public class L8Tests public void L8_ToVector4(byte input) { // Arrange - L8 gray = new(input); + L8 pixel = new(input); // Act - Vector4 actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float scaledInput = input / 255F; @@ -113,12 +111,11 @@ public class L8Tests public void L8_FromRgba32(byte rgb) { // Arrange - L8 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - byte actual = gray.PackedValue; + L8 pixel = L8.FromRgba32(new Rgba32(rgb, rgb, rgb)); + byte actual = pixel.PackedValue; // Assert Assert.Equal(expected, actual); @@ -129,11 +126,10 @@ public class L8Tests public void L8_ToRgba32(byte luminance) { // Arrange - L8 gray = new(luminance); + L8 pixel = new(luminance); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(luminance, actual.R); @@ -146,11 +142,10 @@ public class L8Tests public void L8_FromBgra5551() { // arrange - L8 grey = default; - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - grey.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + L8 grey = L8.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, grey.PackedValue); @@ -167,11 +162,9 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - L8 mirror = default; - mirror.FromRgba32(rgba); + L8 mirror = L8.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -182,11 +175,8 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); - - L8 mirror = default; - mirror.FromRgba32(rgba); + Rgba32 rgba = original.ToRgba32(); + L8 mirror = L8.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -197,11 +187,10 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 l8Vector = original.ToVector4(); - Vector4 rgbaVector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); Assert.Equal(l8Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -212,13 +201,11 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - Vector4 rgbaVector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); - L8 mirror = default; - mirror.FromVector4(rgbaVector); + L8 mirror = L8.FromVector4(rgbaVector); Assert.Equal(original, mirror); } @@ -229,8 +216,7 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 l8Vector = original.ToScaledVector4(); Vector4 rgbaVector = original.ToScaledVector4(); @@ -244,13 +230,11 @@ public class L8Tests { L8 original = new(luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - Vector4 rgbaVector = original.ToScaledVector4(); + Vector4 rgbaVector = rgba.ToScaledVector4(); - L8 mirror = default; - mirror.FromScaledVector4(rgbaVector); + L8 mirror = L8.FromScaledVector4(rgbaVector); Assert.Equal(original, mirror); } diff --git a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs index 612d0f81af..a18b31f6ba 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La16Tests.cs @@ -44,12 +44,11 @@ public class La16Tests public void La16_FromScaledVector4() { // Arrange - La16 gray = default; const ushort expected = 32896; Vector4 scaled = new La16(128, 128).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); + La16 gray = La16.FromScaledVector4(scaled); ushort actual = gray.PackedValue; // Assert @@ -79,11 +78,10 @@ public class La16Tests public void La16_FromVector4(byte luminance) { // Arrange - La16 gray = default; Vector4 vector = new La16(luminance, luminance).ToVector4(); // Act - gray.FromVector4(vector); + La16 gray = La16.FromVector4(vector); byte actualL = gray.L; byte actualA = gray.A; @@ -115,11 +113,10 @@ public class La16Tests public void La16_FromRgba32(byte rgb) { // Arrange - La16 gray = default; byte expected = ColorNumerics.Get8BitBT709Luminance(rgb, rgb, rgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); + La16 gray = La16.FromRgba32(new Rgba32(rgb, rgb, rgb)); byte actual = gray.L; // Assert @@ -135,8 +132,7 @@ public class La16Tests La16 gray = new(luminance, luminance); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = gray.ToRgba32(); // Assert Assert.Equal(luminance, actual.R); @@ -149,11 +145,10 @@ public class La16Tests public void La16_FromBgra5551() { // arrange - La16 grey = default; - byte expected = byte.MaxValue; + const byte expected = byte.MaxValue; // act - grey.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + La16 grey = La16.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, grey.L); @@ -171,11 +166,9 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - La16 mirror = default; - mirror.FromRgba32(rgba); + La16 mirror = La16.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -186,11 +179,9 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); - La16 mirror = default; - mirror.FromRgba32(rgba); + La16 mirror = La16.FromRgba32(rgba); Assert.Equal(original, mirror); } @@ -201,11 +192,10 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 la16Vector = original.ToVector4(); - Vector4 rgbaVector = original.ToVector4(); + Vector4 rgbaVector = rgba.ToVector4(); Assert.Equal(la16Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -216,13 +206,10 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); + Vector4 rgbaVector = rgba.ToVector4(); - Vector4 rgbaVector = original.ToVector4(); - - La16 mirror = default; - mirror.FromVector4(rgbaVector); + La16 mirror = La16.FromVector4(rgbaVector); Assert.Equal(original, mirror); } @@ -233,11 +220,10 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); + Rgba32 rgba = original.ToRgba32(); Vector4 la16Vector = original.ToScaledVector4(); - Vector4 rgbaVector = original.ToScaledVector4(); + Vector4 rgbaVector = rgba.ToScaledVector4(); Assert.Equal(la16Vector, rgbaVector, new ApproximateFloatComparer(1e-5f)); } @@ -248,13 +234,10 @@ public class La16Tests { La16 original = new(luminance, luminance); - Rgba32 rgba = default; - original.ToRgba32(ref rgba); - - Vector4 rgbaVector = original.ToScaledVector4(); + Rgba32 rgba = original.ToRgba32(); + Vector4 rgbaVector = rgba.ToScaledVector4(); - La16 mirror = default; - mirror.FromScaledVector4(rgbaVector); + La16 mirror = La16.FromScaledVector4(rgbaVector); Assert.Equal(original, mirror); } diff --git a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs index 57b70f7843..3c702419d3 100644 --- a/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/La32Tests.cs @@ -40,14 +40,13 @@ public class La32Tests public void La32_FromScaledVector4() { // Arrange - La32 gray = default; const ushort expected = 32767; Vector4 scaled = new La32(expected, expected).ToScaledVector4(); // Act - gray.FromScaledVector4(scaled); - ushort actual = gray.L; - ushort actualA = gray.A; + La32 pixel = La32.FromScaledVector4(scaled); + ushort actual = pixel.L; + ushort actualA = pixel.A; // Assert Assert.Equal(expected, actual); @@ -61,10 +60,10 @@ public class La32Tests public void La32_ToScaledVector4(ushort input) { // Arrange - La32 gray = new(input, input); + La32 pixel = new(input, input); // Act - Vector4 actual = gray.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // Assert float vectorInput = input / 65535F; @@ -78,14 +77,13 @@ public class La32Tests public void La32_FromVector4() { // Arrange - La32 gray = default; const ushort expected = 32767; Vector4 vector = new La32(expected, expected).ToVector4(); // Act - gray.FromVector4(vector); - ushort actual = gray.L; - ushort actualA = gray.A; + La32 pixel = La32.FromVector4(vector); + ushort actual = pixel.L; + ushort actualA = pixel.A; // Assert Assert.Equal(expected, actual); @@ -99,10 +97,10 @@ public class La32Tests public void La32_ToVector4(ushort input) { // Arrange - La32 gray = new(input, input); + La32 pixel = new(input, input); // Act - Vector4 actual = gray.ToVector4(); + Vector4 actual = pixel.ToVector4(); // Assert float vectorInput = input / 65535F; @@ -116,18 +114,17 @@ public class La32Tests public void La32_FromRgba32() { // Arrange - La32 gray = default; const byte rgb = 128; ushort scaledRgb = ColorNumerics.From8BitTo16Bit(rgb); ushort expected = ColorNumerics.Get16BitBT709Luminance(scaledRgb, scaledRgb, scaledRgb); // Act - gray.FromRgba32(new Rgba32(rgb, rgb, rgb)); - ushort actual = gray.L; + La32 pixel = La32.FromRgba32(new Rgba32(rgb, rgb, rgb)); + ushort actual = pixel.L; // Assert Assert.Equal(expected, actual); - Assert.Equal(ushort.MaxValue, gray.A); + Assert.Equal(ushort.MaxValue, pixel.A); } [Theory] @@ -138,11 +135,10 @@ public class La32Tests { // Arrange ushort expected = ColorNumerics.From16BitTo8Bit(input); - La32 gray = new(input, ushort.MaxValue); + La32 pixel = new(input, ushort.MaxValue); // Act - Rgba32 actual = default; - gray.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); // Assert Assert.Equal(expected, actual.R); @@ -155,15 +151,14 @@ public class La32Tests public void La32_FromBgra5551() { // arrange - La32 gray = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - gray.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + La32 pixel = La32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, gray.L); - Assert.Equal(expected, gray.A); + Assert.Equal(expected, pixel.L); + Assert.Equal(expected, pixel.A); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs index 89c0ae69f7..ffbddb1398 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte2Tests.cs @@ -40,10 +40,10 @@ public class NormalizedByte2Tests public void NormalizedByte2_ToScaledVector4() { // arrange - NormalizedByte2 byte2 = new(-Vector2.One); + NormalizedByte2 pixel = new(-Vector2.One); // act - Vector4 actual = byte2.ToScaledVector4(); + Vector4 actual = pixel.ToScaledVector4(); // assert Assert.Equal(0, actual.X); @@ -57,12 +57,11 @@ public class NormalizedByte2Tests { // arrange Vector4 scaled = new NormalizedByte2(-Vector2.One).ToScaledVector4(); - NormalizedByte2 byte2 = default; - uint expected = 0x8181; + const uint expected = 0x8181; // act - byte2.FromScaledVector4(scaled); - uint actual = byte2.PackedValue; + NormalizedByte2 pixel = NormalizedByte2.FromScaledVector4(scaled); + uint actual = pixel.PackedValue; // assert Assert.Equal(expected, actual); @@ -72,14 +71,13 @@ public class NormalizedByte2Tests public void NormalizedByte2_FromBgra5551() { // arrange - NormalizedByte2 normalizedByte2 = default; Vector4 expected = new(1, 1, 0, 1); // act - normalizedByte2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedByte2 pixel = NormalizedByte2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, normalizedByte2.ToVector4()); + Assert.Equal(expected, pixel.ToVector4()); } [Fact] diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs index 297438c65e..5a025f6c4e 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedByte4Tests.cs @@ -18,8 +18,8 @@ public class NormalizedByte4Tests { NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); NormalizedByte4 color2 = new(new Vector4(0.0f)); - NormalizedByte4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - NormalizedByte4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedByte4 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + NormalizedByte4 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -32,9 +32,9 @@ public class NormalizedByte4Tests public void AreNotEqual() { NormalizedByte4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - NormalizedByte4 color2 = new(new Vector4(1.0f)); - NormalizedByte4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - NormalizedByte4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedByte4 color2 = new(new Vector4(1f)); + NormalizedByte4 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + NormalizedByte4 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -80,12 +80,11 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromScaledVector4() { // arrange - NormalizedByte4 pixel = default; Vector4 scaled = new NormalizedByte4(-Vector4.One).ToScaledVector4(); - uint expected = 0x81818181; + const uint expected = 0x81818181; // act - pixel.FromScaledVector4(scaled); + NormalizedByte4 pixel = NormalizedByte4.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -96,138 +95,128 @@ public class NormalizedByte4Tests public void NormalizedByte4_FromArgb32() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + NormalizedByte4 pixel = NormalizedByte4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromBgr24() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromGrey8() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromL8(new L8(byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromGrey16() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromL16(new L16(ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgb24() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgba32() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + NormalizedByte4 pixel = NormalizedByte4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromBgra5551() { // arrange - NormalizedByte4 normalizedByte4 = default; Vector4 expected = Vector4.One; // act - normalizedByte4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedByte4 pixel = NormalizedByte4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert - Assert.Equal(expected, normalizedByte4.ToVector4()); + Assert.Equal(expected, pixel.ToVector4()); } [Fact] public void NormalizedByte4_FromRgb48() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_FromRgba64() { // arrange - NormalizedByte4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedByte4 pixel = NormalizedByte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedByte4_ToRgba32() { // arrange - NormalizedByte4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + NormalizedByte4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs index 4b912d8667..be7b390527 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort2Tests.cs @@ -61,11 +61,10 @@ public class NormalizedShort2Tests { // arrange Vector4 scaled = new NormalizedShort2(-Vector2.One).ToScaledVector4(); - NormalizedShort2 short2 = default; - uint expected = 0x80018001; + const uint expected = 0x80018001; // act - short2.FromScaledVector4(scaled); + NormalizedShort2 short2 = NormalizedShort2.FromScaledVector4(scaled); uint actual = short2.PackedValue; // assert @@ -76,11 +75,10 @@ public class NormalizedShort2Tests public void NormalizedShort2_FromBgra5551() { // arrange - NormalizedShort2 normalizedShort2 = default; Vector4 expected = new(1, 1, 0, 1); // act - normalizedShort2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedShort2 normalizedShort2 = NormalizedShort2.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, normalizedShort2.ToVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs index 0d97658882..281ae7ee52 100644 --- a/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/NormalizedShort4Tests.cs @@ -18,8 +18,8 @@ public class NormalizedShort4Tests { NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); NormalizedShort4 color2 = new(new Vector4(0.0f)); - NormalizedShort4 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - NormalizedShort4 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); + NormalizedShort4 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + NormalizedShort4 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -32,9 +32,9 @@ public class NormalizedShort4Tests public void AreNotEqual() { NormalizedShort4 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - NormalizedShort4 color2 = new(new Vector4(1.0f)); - NormalizedShort4 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - NormalizedShort4 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + NormalizedShort4 color2 = new(new Vector4(1f)); + NormalizedShort4 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + NormalizedShort4 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -81,12 +81,11 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromScaledVector4() { // arrange - NormalizedShort4 pixel = default; Vector4 scaled = new NormalizedShort4(Vector4.One).ToScaledVector4(); - ulong expected = 0x7FFF7FFF7FFF7FFF; + const ulong expected = 0x7FFF7FFF7FFF7FFF; // act - pixel.FromScaledVector4(scaled); + NormalizedShort4 pixel = NormalizedShort4.FromScaledVector4(scaled); ulong actual = pixel.PackedValue; // assert @@ -97,124 +96,115 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromArgb32() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromArgb32(new Argb32(255, 255, 255, 255)); + NormalizedShort4 pixel = NormalizedShort4.FromArgb32(new Argb32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromBgr24() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromGrey8() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromL8(new L8(byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromL8(new L8(byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromGrey16() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromL16(new L16(ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromL16(new L16(ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgb24() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgba32() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgba32(new Rgba32(255, 255, 255, 255)); + NormalizedShort4 pixel = NormalizedShort4.FromRgba32(new Rgba32(255, 255, 255, 255)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgb48() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_FromRgba64() { // arrange - NormalizedShort4 byte4 = default; Vector4 expected = Vector4.One; // act - byte4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + NormalizedShort4 pixel = NormalizedShort4.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert - Assert.Equal(expected, byte4.ToScaledVector4()); + Assert.Equal(expected, pixel.ToScaledVector4()); } [Fact] public void NormalizedShort4_ToRgba32() { // arrange - NormalizedShort4 byte4 = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); + NormalizedShort4 pixel = new(byte.MaxValue, byte.MaxValue, byte.MaxValue, byte.MaxValue); Rgba32 expected = new(Vector4.One); - Rgba32 actual = default; // act - byte4.ToRgba32(ref actual); + Rgba32 actual = pixel.ToRgba32(); Assert.Equal(expected, actual); } @@ -223,11 +213,10 @@ public class NormalizedShort4Tests public void NormalizedShort4_FromBgra5551() { // arrange - NormalizedShort4 normalizedShort4 = default; Vector4 expected = Vector4.One; // act - normalizedShort4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + NormalizedShort4 normalizedShort4 = NormalizedShort4.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, normalizedShort4.ToVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs index 4134922816..2a5c5765ab 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelConverterTests.ReferenceImplementations.cs @@ -14,7 +14,7 @@ public abstract partial class PixelConverterTests { public static byte[] MakeRgba32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -29,7 +29,7 @@ public abstract partial class PixelConverterTests public static byte[] MakeArgb32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -44,7 +44,7 @@ public abstract partial class PixelConverterTests public static byte[] MakeBgra32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -59,7 +59,7 @@ public abstract partial class PixelConverterTests public static byte[] MakeAbgr32ByteArray(byte r, byte g, byte b, byte a) { - var buffer = new byte[256]; + byte[] buffer = new byte[256]; for (int i = 0; i < buffer.Length; i += 4) { @@ -87,49 +87,18 @@ public abstract partial class PixelConverterTests if (typeof(TSourcePixel) == typeof(TDestinationPixel)) { - Span uniformDest = - MemoryMarshal.Cast(destinationPixels); + Span uniformDest = MemoryMarshal.Cast(destinationPixels); sourcePixels.CopyTo(uniformDest); return; } - // L8 and L16 are special implementations of IPixel in that they do not conform to the - // standard RGBA colorspace format and must be converted from RGBA using the special ITU BT709 algorithm. - // One of the requirements of FromScaledVector4/ToScaledVector4 is that it unaware of this and - // packs/unpacks the pixel without and conversion so we employ custom methods do do this. - if (typeof(TDestinationPixel) == typeof(L16)) - { - ref L16 l16Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationPixels)); - for (int i = 0; i < count; i++) - { - ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); - ref L16 dp = ref Unsafe.Add(ref l16Ref, i); - dp.Pack(sp.ToScaledVector4()); - } - - return; - } - - if (typeof(TDestinationPixel) == typeof(L8)) - { - ref L8 l8Ref = ref MemoryMarshal.GetReference(MemoryMarshal.Cast(destinationPixels)); - for (int i = 0; i < count; i++) - { - ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); - ref L8 dp = ref Unsafe.Add(ref l8Ref, i); - dp.ConvertFromRgbaScaledVector4(sp.ToScaledVector4()); - } - - return; - } - // Normal conversion ref TDestinationPixel destRef = ref MemoryMarshal.GetReference(destinationPixels); for (int i = 0; i < count; i++) { ref TSourcePixel sp = ref Unsafe.Add(ref sourceRef, i); ref TDestinationPixel dp = ref Unsafe.Add(ref destRef, i); - dp.FromScaledVector4(sp.ToScaledVector4()); + dp = TDestinationPixel.FromScaledVector4(sp.ToScaledVector4()); } } } diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index 8c16a72df0..b9d9b695ae 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -39,32 +39,32 @@ public abstract class PixelOperationsTests : MeasureFixture } public static TheoryData ArraySizesData => - new TheoryData - { - 0, - 1, - 2, - 7, - 16, - 512, - 513, - 514, - 515, - 516, - 517, - 518, - 519, - 520, - 521, - 522, - 523, - 524, - 525, - 526, - 527, - 528, - 1111 - }; + new() + { + 0, + 1, + 2, + 7, + 16, + 512, + 513, + 514, + 515, + 516, + 517, + 518, + 519, + 520, + 521, + 522, + 523, + 524, + 525, + 526, + 527, + 528, + 1111 + }; protected Configuration Configuration => Configuration.Default; @@ -74,14 +74,14 @@ public abstract class PixelOperationsTests : MeasureFixture internal static TPixel[] CreateExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { - var expected = new TPixel[source.Length]; + TPixel[] expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { Vector4 v = source[i]; vectorModifier?.Invoke(ref v); - expected[i].FromVector4(v); + expected[i] = TPixel.FromVector4(v); } return expected; @@ -89,14 +89,14 @@ public abstract class PixelOperationsTests : MeasureFixture internal static TPixel[] CreateScaledExpectedPixelData(Vector4[] source, RefAction vectorModifier = null) { - var expected = new TPixel[source.Length]; + TPixel[] expected = new TPixel[source.Length]; for (int i = 0; i < expected.Length; i++) { Vector4 v = source[i]; vectorModifier?.Invoke(ref v); - expected[i].FromScaledVector4(v); + expected[i] = TPixel.FromScaledVector4(v); } return expected; @@ -114,18 +114,16 @@ public abstract class PixelOperationsTests : MeasureFixture { // We use 0 - 255 as we have pixel formats that store // the alpha component in less than 8 bits. - const byte Alpha = byte.MinValue; - const byte NoAlpha = byte.MaxValue; + const byte alpha = byte.MinValue; + const byte noAlpha = byte.MaxValue; - TPixel pixel = default; - pixel.FromRgba32(new Rgba32(0, 0, 0, Alpha)); + TPixel pixel = TPixel.FromRgba32(new Rgba32(0, 0, 0, alpha)); - Rgba32 dest = default; - pixel.ToRgba32(ref dest); + Rgba32 dest = pixel.ToRgba32(); bool hasAlpha = TPixel.GetPixelTypeInfo().AlphaRepresentation != PixelAlphaRepresentation.None; - byte expectedAlpha = hasAlpha ? Alpha : NoAlpha; + byte expectedAlpha = hasAlpha ? alpha : noAlpha; Assert.Equal(expectedAlpha, dest.A); } @@ -355,7 +353,7 @@ public abstract class PixelOperationsTests : MeasureFixture { const int count = 2134; TPixel[] source = CreatePixelTestData(count); - var expected = new TDestPixel[count]; + TDestPixel[] expected = new TDestPixel[count]; PixelConverterTests.ReferenceImplementations.To(this.Configuration, source, expected); @@ -476,13 +474,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromArgb32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); + expected[i] = TPixel.FromArgb32(new Argb32(source[i4 + 1], source[i4 + 2], source[i4 + 3], source[i4 + 0])); } TestOperation( @@ -497,12 +495,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var argb = default(Argb32); for (int i = 0; i < count; i++) { int i4 = i * 4; - argb.FromScaledVector4(source[i].ToScaledVector4()); + Argb32 argb = Argb32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = argb.A; expected[i4 + 1] = argb.R; @@ -521,13 +518,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromBgr24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i3 = i * 3; - expected[i].FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); + expected[i] = TPixel.FromBgr24(new Bgr24(source[i3 + 2], source[i3 + 1], source[i3])); } TestOperation( @@ -542,12 +539,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; - var bgr = default(Bgr24); for (int i = 0; i < count; i++) { int i3 = i * 3; - bgr.FromScaledVector4(source[i].ToScaledVector4()); + Bgr24 bgr = Bgr24.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = bgr.B; expected[i3 + 1] = bgr.G; expected[i3 + 2] = bgr.R; @@ -564,13 +560,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromBgra32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); + expected[i] = TPixel.FromBgra32(new Bgra32(source[i4 + 2], source[i4 + 1], source[i4 + 0], source[i4 + 3])); } TestOperation( @@ -585,12 +581,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var bgra = default(Bgra32); for (int i = 0; i < count; i++) { int i4 = i * 4; - bgra.FromScaledVector4(source[i].ToScaledVector4()); + Bgra32 bgra = Bgra32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = bgra.B; expected[i4 + 1] = bgra.G; expected[i4 + 2] = bgra.R; @@ -608,13 +603,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromAbgr32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromAbgr32(new Abgr32(source[i4 + 3], source[i4 + 2], source[i4 + 1], source[i4 + 0])); + expected[i] = TPixel.FromAbgr32(new Abgr32(source[i4 + 3], source[i4 + 2], source[i4 + 1], source[i4 + 0])); } TestOperation( @@ -629,12 +624,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var abgr = default(Abgr32); for (int i = 0; i < count; i++) { int i4 = i * 4; - abgr.FromScaledVector4(source[i].ToScaledVector4()); + Abgr32 abgr = Abgr32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = abgr.A; expected[i4 + 1] = abgr.B; expected[i4 + 2] = abgr.G; @@ -653,14 +647,14 @@ public abstract class PixelOperationsTests : MeasureFixture { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; Bgra5551 bgra = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromBgra5551(bgra); + expected[i] = TPixel.FromBgra5551(bgra); } TestOperation( @@ -676,12 +670,11 @@ public abstract class PixelOperationsTests : MeasureFixture int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - Bgra5551 bgra = default; for (int i = 0; i < count; i++) { int offset = i * size; - bgra.FromScaledVector4(source[i].ToScaledVector4()); + Bgra5551 bgra = Bgra5551.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref bgra); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -699,11 +692,11 @@ public abstract class PixelOperationsTests : MeasureFixture { byte[] sourceBytes = CreateByteTestData(count); L8[] source = sourceBytes.Select(b => new L8(b)).ToArray(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromL8(source[i]); + expected[i] = TPixel.FromL8(source[i]); } TestOperation( @@ -717,11 +710,11 @@ public abstract class PixelOperationsTests : MeasureFixture public void ToL8(int count) { TPixel[] source = CreatePixelTestData(count); - var expected = new L8[count]; + L8[] expected = new L8[count]; for (int i = 0; i < count; i++) { - expected[i].FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = L8.FromScaledVector4(source[i].ToScaledVector4()); } TestOperation( @@ -734,18 +727,13 @@ public abstract class PixelOperationsTests : MeasureFixture [MemberData(nameof(ArraySizesData))] public void FromL16(int count) { - L16[] source = CreateVector4TestData(count).Select(v => - { - L16 g = default; - g.FromVector4(v); - return g; - }).ToArray(); + L16[] source = CreateVector4TestData(count).Select(L16.FromVector4).ToArray(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { - expected[i].FromL16(source[i]); + expected[i] = TPixel.FromL16(source[i]); } TestOperation( @@ -759,11 +747,11 @@ public abstract class PixelOperationsTests : MeasureFixture public void ToL16(int count) { TPixel[] source = CreatePixelTestData(count); - var expected = new L16[count]; + L16[] expected = new L16[count]; for (int i = 0; i < count; i++) { - expected[i].FromScaledVector4(source[i].ToScaledVector4()); + expected[i] = L16.FromScaledVector4(source[i].ToScaledVector4()); } TestOperation( @@ -778,14 +766,14 @@ public abstract class PixelOperationsTests : MeasureFixture { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; La16 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromLa16(la); + expected[i] = TPixel.FromLa16(la); } TestOperation( @@ -801,12 +789,11 @@ public abstract class PixelOperationsTests : MeasureFixture int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - La16 la = default; for (int i = 0; i < count; i++) { int offset = i * size; - la.FromScaledVector4(source[i].ToScaledVector4()); + La16 la = La16.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref la); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -824,14 +811,14 @@ public abstract class PixelOperationsTests : MeasureFixture { int size = Unsafe.SizeOf(); byte[] source = CreateByteTestData(count * size); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int offset = i * size; La32 la = MemoryMarshal.Cast(source.AsSpan().Slice(offset, size))[0]; - expected[i].FromLa32(la); + expected[i] = TPixel.FromLa32(la); } TestOperation( @@ -847,12 +834,11 @@ public abstract class PixelOperationsTests : MeasureFixture int size = Unsafe.SizeOf(); TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * size]; - La32 la = default; for (int i = 0; i < count; i++) { int offset = i * size; - la.FromScaledVector4(source[i].ToScaledVector4()); + La32 la = La32.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes bytes = Unsafe.As(ref la); expected[offset] = bytes[0]; expected[offset + 1] = bytes[1]; @@ -871,13 +857,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromRgb24Bytes(int count) { byte[] source = CreateByteTestData(count * 3); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i3 = i * 3; - expected[i].FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); + expected[i] = TPixel.FromRgb24(new Rgb24(source[i3 + 0], source[i3 + 1], source[i3 + 2])); } TestOperation( @@ -892,12 +878,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 3]; - var rgb = default(Rgb24); for (int i = 0; i < count; i++) { int i3 = i * 3; - rgb.FromScaledVector4(source[i].ToScaledVector4()); + Rgb24 rgb = Rgb24.FromScaledVector4(source[i].ToScaledVector4()); expected[i3] = rgb.R; expected[i3 + 1] = rgb.G; expected[i3 + 2] = rgb.B; @@ -914,13 +899,13 @@ public abstract class PixelOperationsTests : MeasureFixture public void FromRgba32Bytes(int count) { byte[] source = CreateByteTestData(count * 4); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i4 = i * 4; - expected[i].FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); + expected[i] = TPixel.FromRgba32(new Rgba32(source[i4 + 0], source[i4 + 1], source[i4 + 2], source[i4 + 3])); } TestOperation( @@ -935,12 +920,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 4]; - var rgba = default(Rgba32); for (int i = 0; i < count; i++) { int i4 = i * 4; - rgba.FromScaledVector4(source[i].ToScaledVector4()); + Rgba32 rgba = Rgba32.FromScaledVector4(source[i].ToScaledVector4()); expected[i4] = rgba.R; expected[i4 + 1] = rgba.G; expected[i4 + 2] = rgba.B; @@ -959,12 +943,12 @@ public abstract class PixelOperationsTests : MeasureFixture { byte[] source = CreateByteTestData(count * 6); Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i6 = i * 6; - expected[i].FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); + expected[i] = TPixel.FromRgb48(MemoryMarshal.Cast(sourceSpan.Slice(i6, 6))[0]); } TestOperation( @@ -979,12 +963,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 6]; - Rgb48 rgb = default; for (int i = 0; i < count; i++) { int i6 = i * 6; - rgb.FromScaledVector4(source[i].ToScaledVector4()); + Rgb48 rgb = Rgb48.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgb48Bytes = Unsafe.As(ref rgb); expected[i6] = rgb48Bytes[0]; expected[i6 + 1] = rgb48Bytes[1]; @@ -1006,12 +989,12 @@ public abstract class PixelOperationsTests : MeasureFixture { byte[] source = CreateByteTestData(count * 8); Span sourceSpan = source.AsSpan(); - var expected = new TPixel[count]; + TPixel[] expected = new TPixel[count]; for (int i = 0; i < count; i++) { int i8 = i * 8; - expected[i].FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); + expected[i] = TPixel.FromRgba64(MemoryMarshal.Cast(sourceSpan.Slice(i8, 8))[0]); } TestOperation( @@ -1026,12 +1009,11 @@ public abstract class PixelOperationsTests : MeasureFixture { TPixel[] source = CreatePixelTestData(count); byte[] expected = new byte[count * 8]; - Rgba64 rgba = default; for (int i = 0; i < count; i++) { int i8 = i * 8; - rgba.FromScaledVector4(source[i].ToScaledVector4()); + Rgba64 rgba = Rgba64.FromScaledVector4(source[i].ToScaledVector4()); OctetBytes rgba64Bytes = Unsafe.As(ref rgba); expected[i8] = rgba64Bytes[0]; expected[i8 + 1] = rgba64Bytes[1]; @@ -1060,11 +1042,11 @@ public abstract class PixelOperationsTests : MeasureFixture internal static Vector4[] CreateExpectedVector4Data(TPixel[] source, RefAction vectorModifier = null) { - var expected = new Vector4[source.Length]; + Vector4[] expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { - var v = source[i].ToVector4(); + Vector4 v = source[i].ToVector4(); vectorModifier?.Invoke(ref v); @@ -1076,7 +1058,7 @@ public abstract class PixelOperationsTests : MeasureFixture internal static Vector4[] CreateExpectedScaledVector4Data(TPixel[] source, RefAction vectorModifier = null) { - var expected = new Vector4[source.Length]; + Vector4[] expected = new Vector4[source.Length]; for (int i = 0; i < expected.Length; i++) { @@ -1098,7 +1080,7 @@ public abstract class PixelOperationsTests : MeasureFixture where TSource : struct where TDest : struct { - using (var buffers = new TestBuffers(source, expected, preferExactComparison)) + using (TestBuffers buffers = new(source, expected, preferExactComparison)) { action(buffers.SourceBuffer, buffers.ActualDestBuffer); buffers.Verify(); @@ -1107,8 +1089,8 @@ public abstract class PixelOperationsTests : MeasureFixture internal static Vector4[] CreateVector4TestData(int length, RefAction vectorModifier = null) { - var result = new Vector4[length]; - var rnd = new Random(42); // Deterministic random values + Vector4[] result = new Vector4[length]; + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1123,9 +1105,9 @@ public abstract class PixelOperationsTests : MeasureFixture internal static TPixel[] CreatePixelTestData(int length, RefAction vectorModifier = null) { - var result = new TPixel[length]; + TPixel[] result = new TPixel[length]; - var rnd = new Random(42); // Deterministic random values + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1133,7 +1115,7 @@ public abstract class PixelOperationsTests : MeasureFixture vectorModifier?.Invoke(ref v); - result[i].FromVector4(v); + result[i] = TPixel.FromVector4(v); } return result; @@ -1141,9 +1123,9 @@ public abstract class PixelOperationsTests : MeasureFixture internal static TPixel[] CreateScaledPixelTestData(int length, RefAction vectorModifier = null) { - var result = new TPixel[length]; + TPixel[] result = new TPixel[length]; - var rnd = new Random(42); // Deterministic random values + Random rnd = new(42); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1151,7 +1133,7 @@ public abstract class PixelOperationsTests : MeasureFixture vectorModifier?.Invoke(ref v); - result[i].FromScaledVector4(v); + result[i] = TPixel.FromScaledVector4(v); } return result; @@ -1160,7 +1142,7 @@ public abstract class PixelOperationsTests : MeasureFixture internal static byte[] CreateByteTestData(int length, int seed = 42) { byte[] result = new byte[length]; - var rnd = new Random(seed); // Deterministic random values + Random rnd = new(seed); // Deterministic random values for (int i = 0; i < result.Length; i++) { @@ -1171,7 +1153,7 @@ public abstract class PixelOperationsTests : MeasureFixture } internal static Vector4 GetScaledVector(Random rnd) - => new Vector4((float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble()); + => new((float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble(), (float)rnd.NextDouble()); [StructLayout(LayoutKind.Sequential)] internal unsafe struct OctetBytes @@ -1219,7 +1201,7 @@ public abstract class PixelOperationsTests : MeasureFixture { Span expected = MemoryMarshal.Cast(this.ExpectedDestBuffer.AsSpan()); Span actual = MemoryMarshal.Cast(this.ActualDestBuffer.GetSpan()); - var comparer = new ApproximateFloatComparer(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); + ApproximateFloatComparer comparer = new(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); for (int i = 0; i < count; i++) { @@ -1230,7 +1212,7 @@ public abstract class PixelOperationsTests : MeasureFixture { Span expected = this.ExpectedDestBuffer.AsSpan(); Span actual = this.ActualDestBuffer.GetSpan(); - var comparer = new ApproximateFloatComparer(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); + ApproximateFloatComparer comparer = new(TestEnvironment.Is64BitProcess ? 0.0001F : 0.001F); for (int i = 0; i < count; i++) { diff --git a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs index fac7678124..b2790469a1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rg32Tests.cs @@ -13,8 +13,8 @@ public class Rg32Tests [Fact] public void Rg32_PackedValues() { - float x = 0xb6dc; - float y = 0xA59f; + const float x = 0xb6dc; + const float y = 0xA59f; Assert.Equal(0xa59fb6dc, new Rg32(x / 0xffff, y / 0xffff).PackedValue); Assert.Equal(6554U, new Rg32(0.1f, -0.3f).PackedValue); @@ -51,12 +51,11 @@ public class Rg32Tests { // arrange Rg32 rg32 = new(Vector2.One); - Rg32 pixel = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rg32.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Rg32 pixel = Rg32.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -67,11 +66,10 @@ public class Rg32Tests public void Rg32_FromBgra5551() { // arrange - Rg32 rg32 = new(Vector2.One); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rg32.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rg32 rg32 = Rg32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rg32.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs index 385126a65b..6364378c15 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb24Tests.cs @@ -68,8 +68,7 @@ public class Rgb24Tests [Fact] public void FromRgba32() { - Rgb24 rgb = default; - rgb.FromRgba32(new Rgba32(1, 2, 3, 4)); + Rgb24 rgb = Rgb24.FromRgba32(new Rgba32(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -85,8 +84,7 @@ public class Rgb24Tests [Fact] public void FromVector4() { - Rgb24 rgb = default; - rgb.FromVector4(Vec(1, 2, 3, 4)); + Rgb24 rgb = Rgb24.FromVector4(Vec(1, 2, 3, 4)); Assert.Equal(1, rgb.R); Assert.Equal(2, rgb.G); @@ -106,11 +104,10 @@ public class Rgb24Tests { // arrange Rgb24 rgb = new(1, 2, 3); - Rgba32 rgba = default; Rgba32 expected = new(1, 2, 3, 255); // act - rgb.ToRgba32(ref rgba); + Rgba32 rgba = rgb.ToRgba32(); // assert Assert.Equal(expected, rgba); @@ -119,11 +116,8 @@ public class Rgb24Tests [Fact] public void Rgb24_FromBgra5551() { - // arrange - Rgb24 rgb = new(255, 255, 255); - // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgb24 rgb = Rgb24.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(255, rgb.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs index 625a9187fe..764627ee34 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgb48Tests.cs @@ -33,13 +33,12 @@ public class Rgb48Tests public void Rgb48_FromScaledVector4() { // arrange - Rgb48 pixel = default; Rgb48 short3 = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); Rgb48 expected = new(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue); // act Vector4 scaled = short3.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Rgb48 pixel = Rgb48.FromScaledVector4(scaled); // assert Assert.Equal(expected, pixel); @@ -53,8 +52,7 @@ public class Rgb48Tests Rgba32 expected = new(20, 38, 76, 255); // act - Rgba32 actual = default; - rgba48.ToRgba32(ref actual); + Rgba32 actual = rgba48.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -64,11 +62,10 @@ public class Rgb48Tests public void Rgb48_FromBgra5551() { // arrange - Rgb48 rgb = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgb48 rgb = Rgb48.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgb.R); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs index a8243064d3..79a1aefc9c 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba1010102Tests.cs @@ -18,8 +18,8 @@ public class Rgba1010102Tests { Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); Rgba1010102 color2 = new(new Vector4(0.0f)); - Rgba1010102 color3 = new(new Vector4(1.0f, 0.0f, 1.0f, 1.0f)); - Rgba1010102 color4 = new(1.0f, 0.0f, 1.0f, 1.0f); + Rgba1010102 color3 = new(new Vector4(1f, 0.0f, 1f, 1f)); + Rgba1010102 color4 = new(1f, 0.0f, 1f, 1f); Assert.Equal(color1, color2); Assert.Equal(color3, color4); @@ -32,9 +32,9 @@ public class Rgba1010102Tests public void AreNotEqual() { Rgba1010102 color1 = new(0.0f, 0.0f, 0.0f, 0.0f); - Rgba1010102 color2 = new(new Vector4(1.0f)); - Rgba1010102 color3 = new(new Vector4(1.0f, 0.0f, 0.0f, 1.0f)); - Rgba1010102 color4 = new(1.0f, 1.0f, 0.0f, 1.0f); + Rgba1010102 color2 = new(new Vector4(1f)); + Rgba1010102 color3 = new(new Vector4(1f, 0.0f, 0.0f, 1f)); + Rgba1010102 color4 = new(1f, 1f, 0.0f, 1f); Assert.NotEqual(color1, color2); Assert.NotEqual(color3, color4); @@ -43,10 +43,10 @@ public class Rgba1010102Tests [Fact] public void Rgba1010102_PackedValue() { - float x = 0x2db; - float y = 0x36d; - float z = 0x3b7; - float w = 0x1; + const float x = 0x2db; + const float y = 0x36d; + const float z = 0x3b7; + const float w = 0x1; Assert.Equal(0x7B7DB6DBU, new Rgba1010102(x / 0x3ff, y / 0x3ff, z / 0x3ff, w / 3).PackedValue); Assert.Equal(536871014U, new Rgba1010102(0.1f, -0.3f, 0.5f, -0.7f).PackedValue); @@ -84,12 +84,11 @@ public class Rgba1010102Tests { // arrange Rgba1010102 rgba = new(Vector4.One); - Rgba1010102 actual = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rgba.ToScaledVector4(); - actual.FromScaledVector4(scaled); + Rgba1010102 actual = Rgba1010102.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -99,11 +98,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromBgra5551() { // arrange - Rgba1010102 rgba = new(Vector4.One); - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rgba.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba1010102 rgba = Rgba1010102.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgba.PackedValue); @@ -113,11 +111,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromArgb32() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromArgb32(new Argb32(255, 255, 255, 255)); + Rgba1010102 rgba = Rgba1010102.FromArgb32(new Argb32(255, 255, 255, 255)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -127,14 +124,12 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgba32() { // arrange - Rgba1010102 rgba1 = default; - Rgba1010102 rgba2 = default; - uint expectedPackedValue1 = uint.MaxValue; - uint expectedPackedValue2 = 0xFFF003FF; + const uint expectedPackedValue1 = uint.MaxValue; + const uint expectedPackedValue2 = 0xFFF003FF; // act - rgba1.FromRgba32(new Rgba32(255, 255, 255, 255)); - rgba2.FromRgba32(new Rgba32(255, 0, 255, 255)); + Rgba1010102 rgba1 = Rgba1010102.FromRgba32(new Rgba32(255, 255, 255, 255)); + Rgba1010102 rgba2 = Rgba1010102.FromRgba32(new Rgba32(255, 0, 255, 255)); // assert Assert.Equal(expectedPackedValue1, rgba1.PackedValue); @@ -145,11 +140,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromBgr24() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromBgr24(new Bgr24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -159,11 +153,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromGrey8() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromL8(new L8(byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -173,11 +166,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromGrey16() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromL16(new L16(ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -187,11 +179,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgb24() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgb24(new Rgb24(byte.MaxValue, byte.MaxValue, byte.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -201,11 +192,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgb48() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgb48(new Rgb48(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -215,11 +205,10 @@ public class Rgba1010102Tests public void Rgba1010102_FromRgba64() { // arrange - Rgba1010102 rgba = default; - uint expectedPackedValue = uint.MaxValue; + const uint expectedPackedValue = uint.MaxValue; // act - rgba.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); + Rgba1010102 rgba = Rgba1010102.FromRgba64(new Rgba64(ushort.MaxValue, ushort.MaxValue, ushort.MaxValue, ushort.MaxValue)); // assert Assert.Equal(expectedPackedValue, rgba.PackedValue); @@ -240,8 +229,7 @@ public class Rgba1010102Tests Rgba32 expected = new(25, 0, 128, 0); // act - Rgba32 actual = default; - rgba.ToRgba32(ref actual); + Rgba32 actual = rgba.ToRgba32(); // assert Assert.Equal(expected, actual); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs index 35fab151c7..6d56185ecf 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba32Tests.cs @@ -164,12 +164,11 @@ public class Rgba32Tests { // arrange Rgba32 rgba = new(Vector4.One); - Rgba32 actual = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act Vector4 scaled = rgba.ToScaledVector4(); - actual.FromScaledVector4(scaled); + Rgba32 actual = Rgba32.FromScaledVector4(scaled); // assert Assert.Equal(expected, actual.PackedValue); @@ -187,11 +186,10 @@ public class Rgba32Tests { // arrange Rgba32 rgba = new(+0.1f, -0.3f, +0.5f, -0.7f); - Rgba32 actual = default; Rgba32 expected = new(0x1a, 0, 0x80, 0); // act - actual.FromRgba32(rgba); + Rgba32 actual = Rgba32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -201,13 +199,11 @@ public class Rgba32Tests public void Rgba32_FromRgba32_ToRgba32() { // arrange - Rgba32 rgba = default; - Rgba32 actual = default; Rgba32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromRgba32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromRgba32(expected); + Rgba32 actual = Rgba32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -217,13 +213,11 @@ public class Rgba32Tests public void Rgba32_FromBgra32_ToRgba32() { // arrange - Rgba32 rgba = default; - Bgra32 actual = default; Bgra32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromBgra32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromBgra32(expected); + Bgra32 actual = Bgra32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -233,13 +227,11 @@ public class Rgba32Tests public void Rgba32_FromAbgr32_ToRgba32() { // arrange - Rgba32 rgba = default; - Abgr32 actual = default; Abgr32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromAbgr32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromAbgr32(expected); + Abgr32 actual = Abgr32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -249,13 +241,11 @@ public class Rgba32Tests public void Rgba32_FromArgb32_ToArgb32() { // arrange - Rgba32 rgba = default; - Argb32 actual = default; Argb32 expected = new(0x1a, 0, 0x80, 0); // act - rgba.FromArgb32(expected); - actual.FromRgba32(rgba); + Rgba32 rgba = Rgba32.FromArgb32(expected); + Argb32 actual = Argb32.FromRgba32(rgba); // assert Assert.Equal(expected, actual); @@ -265,13 +255,11 @@ public class Rgba32Tests public void Rgba32_FromRgb48() { // arrange - Rgba32 input = default; - Rgb48 actual = default; Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Rgba32 input = Rgba32.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -281,13 +269,11 @@ public class Rgba32Tests public void Rgba32_FromRgba64() { // arrange - Rgba32 input = default; - Rgba64 actual = default; Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Rgba32 input = Rgba32.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -297,11 +283,10 @@ public class Rgba32Tests public void Rgba32_FromBgra5551() { // arrange - Rgba32 rgb = default; - uint expected = 0xFFFFFFFF; + const uint expected = 0xFFFFFFFF; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba32 rgb = Rgba32.FromBgra5551(new Bgra5551(1f, 1f, 1f, 1f)); // assert Assert.Equal(expected, rgb.PackedValue); diff --git a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs index 4f335b1e81..694d0ace10 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Rgba64Tests.cs @@ -69,8 +69,7 @@ public class Rgba64Tests // act Vector4 scaled = source.ToScaledVector4(); - Rgba64 actual = default; - actual.FromScaledVector4(scaled); + Rgba64 actual = Rgba64.FromScaledVector4(scaled); // assert Assert.Equal(source, actual); @@ -79,10 +78,9 @@ public class Rgba64Tests [Fact] public void Rgba64_Clamping() { - Rgba64 zero = default; - Rgba64 one = default; - zero.FromVector4(Vector4.One * -1234.0f); - one.FromVector4(Vector4.One * 1234.0f); + Rgba64 zero = Rgba64.FromVector4(Vector4.One * -1234.0f); + Rgba64 one = Rgba64.FromVector4(Vector4.One * 1234.0f); + Assert.Equal(Vector4.Zero, zero.ToVector4()); Assert.Equal(Vector4.One, one.ToVector4()); } @@ -92,11 +90,10 @@ public class Rgba64Tests { // arrange Rgba64 rgba64 = new(5140, 9766, 19532, 29555); - Rgba32 actual = default; Rgba32 expected = new(20, 38, 76, 115); // act - rgba64.ToRgba32(ref actual); + Rgba32 actual = rgba64.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -106,11 +103,10 @@ public class Rgba64Tests public void Rgba64_FromBgra5551() { // arrange - Rgba64 rgba = default; - ushort expected = ushort.MaxValue; + const ushort expected = ushort.MaxValue; // act - rgba.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Rgba64 rgba = Rgba64.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, rgba.R); @@ -147,8 +143,7 @@ public class Rgba64Tests Rgba32 source = new(20, 38, 76, 115); Rgba64 expected = new(5140, 9766, 19532, 29555); - Rgba64 actual = default; - actual.FromRgba32(source); + Rgba64 actual = Rgba64.FromRgba32(source); Assert.Equal(expected, actual); } @@ -217,8 +212,7 @@ public class Rgba64Tests public void ConstructFrom_Vector4() { Vector4 source = new(0f, 0.2f, 0.5f, 1f); - Rgba64 expected = default; - expected.FromScaledVector4(source); + Rgba64 expected = Rgba64.FromScaledVector4(source); Rgba64 actual = new(source); diff --git a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs index b263bf8ea7..5273482efb 100644 --- a/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/RgbaVectorTests.cs @@ -119,13 +119,11 @@ public class RgbaVectorTests public void RgbaVector_FromRgb48() { // arrange - RgbaVector input = default; - Rgb48 actual = default; Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + RgbaVector input = RgbaVector.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -135,13 +133,11 @@ public class RgbaVectorTests public void RgbaVector_FromRgba64() { // arrange - RgbaVector input = default; - Rgba64 actual = default; Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + RgbaVector input = RgbaVector.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -151,11 +147,10 @@ public class RgbaVectorTests public void RgbaVector_FromBgra5551() { // arrange - RgbaVector rgb = default; Vector4 expected = Vector4.One; // act - rgb.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + RgbaVector rgb = RgbaVector.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, rgb.ToScaledVector4()); @@ -165,11 +160,10 @@ public class RgbaVectorTests public void RgbaVector_FromGrey16() { // arrange - RgbaVector rgba = default; Vector4 expected = Vector4.One; // act - rgba.FromL16(new L16(ushort.MaxValue)); + RgbaVector rgba = RgbaVector.FromL16(new L16(ushort.MaxValue)); // assert Assert.Equal(expected, rgba.ToScaledVector4()); @@ -179,11 +173,10 @@ public class RgbaVectorTests public void RgbaVector_FromGrey8() { // arrange - RgbaVector rgba = default; Vector4 expected = Vector4.One; // act - rgba.FromL8(new L8(byte.MaxValue)); + RgbaVector rgba = RgbaVector.FromL8(new L8(byte.MaxValue)); // assert Assert.Equal(expected, rgba.ToScaledVector4()); @@ -197,10 +190,8 @@ public class RgbaVectorTests using Image source = new(Configuration.Default, 1, 1, green); using Image clone = source.CloneAs(); - Rgba32 srcColor = default; - Rgba32 cloneColor = default; - source[0, 0].ToRgba32(ref srcColor); - clone[0, 0].ToRgba32(ref cloneColor); + Rgba32 srcColor = source[0, 0].ToRgba32(); + Rgba32 cloneColor = clone[0, 0].ToRgba32(); Assert.Equal(srcColor, cloneColor); } diff --git a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs index 1143925cb3..f23da0c7a6 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short2Tests.cs @@ -68,13 +68,12 @@ public class Short2Tests public void Short2_FromScaledVector4() { // arrange - Short2 pixel = default; Short2 short2 = new(Vector2.One * 0x7FFF); const ulong expected = 0x7FFF7FFF; // act Vector4 scaled = short2.ToScaledVector4(); - pixel.FromScaledVector4(scaled); + Short2 pixel = Short2.FromScaledVector4(scaled); uint actual = pixel.PackedValue; // assert @@ -86,11 +85,10 @@ public class Short2Tests { // arrange Short2 short2 = new(127.5f, -5.3f); - Rgba32 actual = default; Rgba32 expected = new(128, 127, 0, 255); // act - short2.ToRgba32(ref actual); + Rgba32 actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -100,13 +98,11 @@ public class Short2Tests public void Short2_FromRgba32_ToRgba32() { // arrange - Short2 short2 = default; - Rgba32 actual = default; Rgba32 expected = new(20, 38, 0, 255); // act - short2.FromRgba32(expected); - short2.ToRgba32(ref actual); + Short2 short2 = Short2.FromRgba32(expected); + Rgba32 actual = short2.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -116,13 +112,11 @@ public class Short2Tests public void Short2_FromRgb48() { // arrange - Short2 input = default; - Rgb48 actual = default; Rgb48 expected = new(65535, 65535, 0); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short2 input = Short2.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -132,13 +126,11 @@ public class Short2Tests public void Short2_FromRgba64() { // arrange - Short2 input = default; - Rgba64 actual = default; Rgba64 expected = new(65535, 65535, 0, 65535); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short2 input = Short2.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -147,11 +139,8 @@ public class Short2Tests [Fact] public void Short2_FromBgra5551() { - // arrange - Short2 short2 = default; - // act - short2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Short2 short2 = Short2.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Vector4 actual = short2.ToScaledVector4(); diff --git a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs index ab3cc3b6e5..819ff0e1e5 100644 --- a/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/Short4Tests.cs @@ -60,8 +60,7 @@ public class Short4Tests const long expected = 0x7FFF7FFF7FFF7FFF; // act - Short4 pixel = default; - pixel.FromScaledVector4(scaled); + Short4 pixel = Short4.FromScaledVector4(scaled); // assert Assert.Equal((ulong)expected, pixel.PackedValue); @@ -88,11 +87,10 @@ public class Short4Tests { // arrange Short4 shortValue = new(11547, 12653, 29623, 193); - Rgba32 actual = default; Rgba32 expected = new(172, 177, 243, 128); // act - shortValue.ToRgba32(ref actual); + Rgba32 actual = shortValue.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -102,13 +100,11 @@ public class Short4Tests public void Short4_FromRgba32_ToRgba32() { // arrange - Short4 short4 = default; - Rgba32 actual = default; Rgba32 expected = new(20, 38, 0, 255); // act - short4.FromRgba32(expected); - short4.ToRgba32(ref actual); + Short4 short4 = Short4.FromRgba32(expected); + Rgba32 actual = short4.ToRgba32(); // assert Assert.Equal(expected, actual); @@ -118,15 +114,12 @@ public class Short4Tests public void Short4_FromBgra32_ToRgba32() { // arrange - Short4 short4 = default; - Bgra32 actual = default; Bgra32 expected = new(20, 38, 0, 255); // act - short4.FromBgra32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromBgra32(expected); + Rgba32 temp = short4.ToRgba32(); + Bgra32 actual = Bgra32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -136,15 +129,12 @@ public class Short4Tests public void Short4_FromArgb32_ToRgba32() { // arrange - Short4 short4 = default; - Argb32 actual = default; Argb32 expected = new(20, 38, 0, 255); // act - short4.FromArgb32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromArgb32(expected); + Rgba32 temp = short4.ToRgba32(); + Argb32 actual = Argb32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -154,15 +144,12 @@ public class Short4Tests public void Short4_FromAbgrb32_ToRgba32() { // arrange - Short4 short4 = default; - Abgr32 actual = default; Abgr32 expected = new(20, 38, 0, 255); // act - short4.FromAbgr32(expected); - Rgba32 temp = default; - short4.ToRgba32(ref temp); - actual.FromRgba32(temp); + Short4 short4 = Short4.FromAbgr32(expected); + Rgba32 temp = short4.ToRgba32(); + Abgr32 actual = Abgr32.FromRgba32(temp); // assert Assert.Equal(expected, actual); @@ -172,13 +159,11 @@ public class Short4Tests public void Short4_FromRgb48_ToRgb48() { // arrange - Short4 input = default; - Rgb48 actual = default; Rgb48 expected = new(65535, 0, 65535); // act - input.FromRgb48(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short4 input = Short4.FromRgb48(expected); + Rgb48 actual = Rgb48.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -188,13 +173,11 @@ public class Short4Tests public void Short4_FromRgba64_ToRgba64() { // arrange - Short4 input = default; - Rgba64 actual = default; Rgba64 expected = new(65535, 0, 65535, 0); // act - input.FromRgba64(expected); - actual.FromScaledVector4(input.ToScaledVector4()); + Short4 input = Short4.FromRgba64(expected); + Rgba64 actual = Rgba64.FromScaledVector4(input.ToScaledVector4()); // assert Assert.Equal(expected, actual); @@ -204,11 +187,10 @@ public class Short4Tests public void Short4_FromBgra5551() { // arrange - Short4 short4 = default; Vector4 expected = Vector4.One; // act - short4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); + Short4 short4 = Short4.FromBgra5551(new Bgra5551(1.0f, 1.0f, 1.0f, 1.0f)); // assert Assert.Equal(expected, short4.ToScaledVector4()); diff --git a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs index 75e3b693ce..651f6fe7f8 100644 --- a/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/UnPackedPixelTests.cs @@ -84,10 +84,8 @@ public class UnPackedPixelTests Rgba32 color = new(24, 48, 96, 192); RgbaVector colorVector = new(24 / 255F, 48 / 255F, 96 / 255F, 192 / 255F); - Rgba32 rgba = default; - Rgba32 rgbaVector = default; - color.ToRgba32(ref rgba); - colorVector.ToRgba32(ref rgbaVector); + Rgba32 rgba = color.ToRgba32(); + Rgba32 rgbaVector = colorVector.ToRgba32(); Assert.Equal(rgba, rgbaVector); } diff --git a/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs b/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs index cd61d68be5..81ba1693d2 100644 --- a/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs +++ b/tests/ImageSharp.Tests/Processing/IntegralImageTests.cs @@ -21,14 +21,7 @@ public class IntegralImageTests : BaseImageOperationsExtensionTest Buffer2D integralBuffer = image.CalculateIntegralImage(); // Assert: - VerifySumValues(provider, integralBuffer, (Rgba32 pixel) => - { - L8 outputPixel = default; - - outputPixel.FromRgba32(pixel); - - return outputPixel.PackedValue; - }); + VerifySumValues(provider, integralBuffer, (Rgba32 pixel) => L8.FromRgba32(pixel).PackedValue); } [Theory] @@ -45,14 +38,7 @@ public class IntegralImageTests : BaseImageOperationsExtensionTest Buffer2D integralBuffer = image.CalculateIntegralImage(interest); // Assert: - VerifySumValues(provider, integralBuffer, interest, (Rgba32 pixel) => - { - L8 outputPixel = default; - - outputPixel.FromRgba32(pixel); - - return outputPixel.PackedValue; - }); + VerifySumValues(provider, integralBuffer, interest, (Rgba32 pixel) => L8.FromRgba32(pixel).PackedValue); } [Theory] @@ -88,7 +74,7 @@ public class IntegralImageTests : BaseImageOperationsExtensionTest private static void VerifySumValues( TestImageProvider provider, Buffer2D integralBuffer, - System.Func getPixel) + Func getPixel) where TPixel : unmanaged, IPixel => VerifySumValues(provider, integralBuffer, integralBuffer.Bounds(), getPixel); @@ -96,7 +82,7 @@ public class IntegralImageTests : BaseImageOperationsExtensionTest TestImageProvider provider, Buffer2D integralBuffer, Rectangle bounds, - System.Func getPixel) + Func getPixel) where TPixel : unmanaged, IPixel { Buffer2DRegion image = provider.GetImage().GetRootFramePixelBuffer().GetRegion(bounds); diff --git a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs index 0fc5e286da..2ed003fdd2 100644 --- a/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs +++ b/tests/ImageSharp.Tests/Processing/Processors/Transforms/AffineTransformTests.cs @@ -21,8 +21,8 @@ public class AffineTransformTests /// angleDeg, sx, sy, tx, ty /// public static readonly TheoryData TransformValues - = new TheoryData - { + = new() + { { 0, 1, 1, 0, 0 }, { 50, 1, 1, 0, 0 }, { 0, 1, 1, 20, 10 }, @@ -35,7 +35,7 @@ public class AffineTransformTests { 0, 1f, 2f, 0, 0 }, }; - public static readonly TheoryData ResamplerNames = new TheoryData + public static readonly TheoryData ResamplerNames = new() { nameof(KnownResamplers.Bicubic), nameof(KnownResamplers.Box), @@ -55,8 +55,8 @@ public class AffineTransformTests }; public static readonly TheoryData Transform_DoesNotCreateEdgeArtifacts_ResamplerNames = - new TheoryData - { + new() + { nameof(KnownResamplers.NearestNeighbor), nameof(KnownResamplers.Triangle), nameof(KnownResamplers.Bicubic), @@ -75,16 +75,14 @@ public class AffineTransformTests where TPixel : unmanaged, IPixel { IResampler resampler = GetResampler(resamplerName); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(30); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(30); - image.Mutate(c => c.Transform(builder, resampler)); - image.DebugSave(provider, resamplerName); + image.Mutate(c => c.Transform(builder, resampler)); + image.DebugSave(provider, resamplerName); - VerifyAllPixelsAreWhiteOrTransparent(image); - } + VerifyAllPixelsAreWhiteOrTransparent(image); } [Theory] @@ -98,22 +96,20 @@ public class AffineTransformTests float ty) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(angleDeg) - .AppendScale(new SizeF(sx, sy)) - .AppendTranslation(new PointF(tx, ty)); + using Image image = provider.GetImage(); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(sx, sy)) + .AppendTranslation(new PointF(tx, ty)); - this.PrintMatrix(builder.BuildMatrix(image.Size)); + this.PrintMatrix(builder.BuildMatrix(image.Size)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); - FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; - image.DebugSave(provider, testOutputDetails); - image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); - } + FormattableString testOutputDetails = $"R({angleDeg})_S({sx},{sy})_T({tx},{ty})"; + image.DebugSave(provider, testOutputDetails); + image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); } [Theory] @@ -121,23 +117,21 @@ public class AffineTransformTests public void Transform_RotateScale_ManuallyCentered(TestImageProvider provider, float angleDeg, float s) where TPixel : unmanaged, IPixel { - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(angleDeg) - .AppendScale(new SizeF(s, s)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(angleDeg) + .AppendScale(new SizeF(s, s)); - image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); + image.Mutate(i => i.Transform(builder, KnownResamplers.Bicubic)); - FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; - image.DebugSave(provider, testOutputDetails); - image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); - } + FormattableString testOutputDetails = $"R({angleDeg})_S({s})"; + image.DebugSave(provider, testOutputDetails); + image.CompareToReferenceOutput(ValidatorComparer, provider, testOutputDetails); } public static readonly TheoryData Transform_IntoRectangle_Data = - new TheoryData - { + new() + { { 0, 0, 10, 10 }, { 0, 0, 5, 10 }, { 0, 0, 10, 5 }, @@ -155,19 +149,17 @@ public class AffineTransformTests public void Transform_FromSourceRectangle1(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var rectangle = new Rectangle(48, 0, 48, 24); + Rectangle rectangle = new(48, 0, 48, 24); - using (Image image = provider.GetImage()) - { - image.DebugSave(provider, $"_original"); - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendScale(new SizeF(2, 1.5F)); + using Image image = provider.GetImage(); + image.DebugSave(provider, $"_original"); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(2, 1.5F)); - image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } + image.DebugSave(provider); + image.CompareToReferenceOutput(ValidatorComparer, provider); } [Theory] @@ -175,18 +167,16 @@ public class AffineTransformTests public void Transform_FromSourceRectangle2(TestImageProvider provider) where TPixel : unmanaged, IPixel { - var rectangle = new Rectangle(0, 24, 48, 24); + Rectangle rectangle = new(0, 24, 48, 24); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendScale(new SizeF(1F, 2F)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendScale(new SizeF(1F, 2F)); - image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); + image.Mutate(i => i.Transform(rectangle, builder, KnownResamplers.Spline)); - image.DebugSave(provider); - image.CompareToReferenceOutput(ValidatorComparer, provider); - } + image.DebugSave(provider); + image.CompareToReferenceOutput(ValidatorComparer, provider); } [Theory] @@ -195,17 +185,15 @@ public class AffineTransformTests where TPixel : unmanaged, IPixel { IResampler sampler = GetResampler(resamplerName); - using (Image image = provider.GetImage()) - { - AffineTransformBuilder builder = new AffineTransformBuilder() - .AppendRotationDegrees(50) - .AppendScale(new SizeF(.6F, .6F)); + using Image image = provider.GetImage(); + AffineTransformBuilder builder = new AffineTransformBuilder() + .AppendRotationDegrees(50) + .AppendScale(new SizeF(.6F, .6F)); - image.Mutate(i => i.Transform(builder, sampler)); + image.Mutate(i => i.Transform(builder, sampler)); - image.DebugSave(provider, resamplerName); - image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); - } + image.DebugSave(provider, resamplerName); + image.CompareToReferenceOutput(ValidatorComparer, provider, resamplerName); } [Theory] @@ -224,7 +212,7 @@ public class AffineTransformTests [Fact] public void Issue1911() { - using var image = new Image(100, 100); + using Image image = new(100, 100); image.Mutate(x => x = x.Transform(new Rectangle(0, 0, 99, 100), Matrix3x2.Identity, new Size(99, 100), KnownResamplers.Lanczos2)); Assert.Equal(99, image.Width); @@ -254,7 +242,7 @@ public class AffineTransformTests { using Image image = provider.GetImage(); - var m = Matrix3x2.CreateRotation(radians, new Vector2(50, 50)); + Matrix3x2 m = Matrix3x2.CreateRotation(radians, new Vector2(50, 50)); Rectangle r = new(25, 25, 50, 50); image.Mutate(x => x.Transform(r, m, new Size(100, 100), KnownResamplers.Bicubic)); image.DebugSave(provider, testOutputDetails: radians); @@ -263,12 +251,8 @@ public class AffineTransformTests private static IResampler GetResampler(string name) { - PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name); - - if (property is null) - { - throw new Exception($"No resampler named {name}"); - } + PropertyInfo property = typeof(KnownResamplers).GetTypeInfo().GetProperty(name) + ?? throw new InvalidOperationException($"No resampler named {name}"); return (IResampler)property.GetValue(null); } @@ -277,11 +261,10 @@ public class AffineTransformTests where TPixel : unmanaged, IPixel { Assert.True(image.Frames.RootFrame.DangerousTryGetSinglePixelMemory(out Memory data)); - var white = new Rgb24(255, 255, 255); + Rgb24 white = new(255, 255, 255); foreach (TPixel pixel in data.Span) { - Rgba32 rgba = default; - pixel.ToRgba32(ref rgba); + Rgba32 rgba = pixel.ToRgba32(); if (rgba.A == 0) { continue; diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 983cf4d46b..89e2a11a90 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -263,6 +263,12 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public struct TestPixelForAgnosticDecode : IPixel { + public readonly Rgba32 ToRgba32() => default; + + public readonly Vector4 ToScaledVector4() => default; + + public readonly Vector4 ToVector4() => default; + public static PixelTypeInfo GetPixelTypeInfo() => PixelTypeInfo.Create( PixelComponentInfo.Create(2, 8, 8), @@ -271,73 +277,35 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat public PixelOperations CreatePixelOperations() => new(); - public void FromScaledVector4(Vector4 vector) - { - } + public static TestPixelForAgnosticDecode FromScaledVector4(Vector4 vector) => default; - public Vector4 ToScaledVector4() => default; + public static TestPixelForAgnosticDecode FromVector4(Vector4 vector) => default; - public void FromVector4(Vector4 vector) - { - } + public static TestPixelForAgnosticDecode FromAbgr32(Abgr32 source) => default; - public Vector4 ToVector4() => default; + public static TestPixelForAgnosticDecode FromArgb32(Argb32 source) => default; - public void FromArgb32(Argb32 source) - { - } + public static TestPixelForAgnosticDecode FromBgra5551(Bgra5551 source) => default; - public void FromBgra5551(Bgra5551 source) - { - } - - public void FromBgr24(Bgr24 source) - { - } - - public void FromBgra32(Bgra32 source) - { - } - - public void FromAbgr32(Abgr32 source) - { - } + public static TestPixelForAgnosticDecode FromBgr24(Bgr24 source) => default; - public void FromL8(L8 source) - { - } + public static TestPixelForAgnosticDecode FromBgra32(Bgra32 source) => default; - public void FromL16(L16 source) - { - } + public static TestPixelForAgnosticDecode FromL8(L8 source) => default; - public void FromLa16(La16 source) - { - } + public static TestPixelForAgnosticDecode FromL16(L16 source) => default; - public void FromLa32(La32 source) - { - } + public static TestPixelForAgnosticDecode FromLa16(La16 source) => default; - public void FromRgb24(Rgb24 source) - { - } + public static TestPixelForAgnosticDecode FromLa32(La32 source) => default; - public void FromRgba32(Rgba32 source) - { - } + public static TestPixelForAgnosticDecode FromRgb24(Rgb24 source) => default; - public void ToRgba32(ref Rgba32 dest) - { - } + public static TestPixelForAgnosticDecode FromRgba32(Rgba32 source) => default; - public void FromRgb48(Rgb48 source) - { - } + public static TestPixelForAgnosticDecode FromRgb48(Rgb48 source) => default; - public void FromRgba64(Rgba64 source) - { - } + public static TestPixelForAgnosticDecode FromRgba64(Rgba64 source) => default; public bool Equals(TestPixelForAgnosticDecode other) => false; } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs index ccb149ca32..813ed505d8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/BasicTestPatternProvider.cs @@ -14,9 +14,7 @@ public abstract partial class TestImageProvider : IXunitSerializable } public virtual TPixel GetExpectedBasicTestPatternPixelAt(int x, int y) - { - throw new NotSupportedException("GetExpectedBasicTestPatternPixelAt(x,y) only works with BasicTestPattern"); - } + => throw new NotSupportedException("GetExpectedBasicTestPatternPixelAt(x,y) only works with BasicTestPattern"); private class BasicTestPatternProvider : BlankProvider { @@ -41,7 +39,7 @@ public abstract partial class TestImageProvider : IXunitSerializable public override Image GetImage() { - var result = new Image(this.Configuration, this.Width, this.Height); + Image result = new(this.Configuration, this.Width, this.Height); result.ProcessPixelRows(accessor => { int midY = this.Height / 2; @@ -51,16 +49,16 @@ public abstract partial class TestImageProvider : IXunitSerializable { Span row = accessor.GetRowSpan(y); - row.Slice(0, midX).Fill(TopLeftColor); - row.Slice(midX, this.Width - midX).Fill(TopRightColor); + row[..midX].Fill(TopLeftColor); + row[midX..this.Width].Fill(TopRightColor); } for (int y = midY; y < this.Height; y++) { Span row = accessor.GetRowSpan(y); - row.Slice(0, midX).Fill(BottomLeftColor); - row.Slice(midX, this.Width - midX).Fill(BottomRightColor); + row[..midX].Fill(BottomLeftColor); + row[midX..this.Width].Fill(BottomRightColor); } }); @@ -76,17 +74,10 @@ public abstract partial class TestImageProvider : IXunitSerializable { return x < midX ? TopLeftColor : TopRightColor; } - else - { - return x < midX ? BottomLeftColor : BottomRightColor; - } - } - private static TPixel GetBottomRightColor() - { - TPixel bottomRightColor = default; - bottomRightColor.FromScaledVector4(new Vector4(1f, 0f, 1f, 0.5f)); - return bottomRightColor; + return x < midX ? BottomLeftColor : BottomRightColor; } + + private static TPixel GetBottomRightColor() => TPixel.FromScaledVector4(new Vector4(1f, 0f, 1f, 0.5f)); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs index 63307f7e21..405d048fc5 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImageProviders/TestPatternProvider.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Numerics; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.PixelFormats; using Xunit.Abstractions; @@ -15,19 +16,19 @@ public abstract partial class TestImageProvider : IXunitSerializable /// private class TestPatternProvider : BlankProvider { - private static readonly Dictionary> TestImages = new Dictionary>(); + private static readonly Dictionary> TestImages = []; private static readonly TPixel[] BlackWhitePixels = - { - Color.Black.ToPixel(), - Color.White.ToPixel() - }; + [ + Color.Black.ToPixel(), + Color.White.ToPixel() + ]; private static readonly TPixel[] PinkBluePixels = - { - Color.HotPink.ToPixel(), - Color.Blue.ToPixel() - }; + [ + Color.HotPink.ToPixel(), + Color.Blue.ToPixel() + ]; public TestPatternProvider(int width, int height) : base(width, height) @@ -47,14 +48,15 @@ public abstract partial class TestImageProvider : IXunitSerializable { lock (TestImages) { - if (!TestImages.ContainsKey(this.SourceFileOrDescription)) + if (!TestImages.TryGetValue(this.SourceFileOrDescription, out Image value)) { - var image = new Image(this.Width, this.Height); + Image image = new(this.Width, this.Height); DrawTestPattern(image); - TestImages.Add(this.SourceFileOrDescription, image); + value = image; + TestImages.Add(this.SourceFileOrDescription, value); } - return TestImages[this.SourceFileOrDescription].Clone(this.Configuration); + return value.Clone(this.Configuration); } } @@ -75,12 +77,13 @@ public abstract partial class TestImageProvider : IXunitSerializable /// /// Fills the top right quadrant with alternating solid vertical bars. /// + /// The pixel buffer. private static void VerticalBars(Buffer2D pixels) { // topLeft int left = pixels.Width / 2; int right = pixels.Width; - int top = 0; + const int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 12; if (stride < 1) @@ -96,7 +99,7 @@ public abstract partial class TestImageProvider : IXunitSerializable if (x % stride == 0) { p++; - p = p % PinkBluePixels.Length; + p %= PinkBluePixels.Length; } pixels[x, y] = PinkBluePixels[p]; @@ -107,12 +110,13 @@ public abstract partial class TestImageProvider : IXunitSerializable /// /// fills the top left quadrant with a black and white checker board. /// + /// The pixel buffer. private static void BlackWhiteChecker(Buffer2D pixels) { // topLeft - int left = 0; + const int left = 0; int right = pixels.Width / 2; - int top = 0; + const int top = 0; int bottom = pixels.Height / 2; int stride = pixels.Width / 6; @@ -122,63 +126,62 @@ public abstract partial class TestImageProvider : IXunitSerializable if (y % stride is 0) { p++; - p = p % BlackWhitePixels.Length; + p %= BlackWhitePixels.Length; } - int pstart = p; + int pStart = p; for (int x = left; x < right; x++) { if (x % stride is 0) { p++; - p = p % BlackWhitePixels.Length; + p %= BlackWhitePixels.Length; } pixels[x, y] = BlackWhitePixels[p]; } - p = pstart; + p = pStart; } } /// /// Fills the bottom left quadrant with 3 horizontal bars in Red, Green and Blue with a alpha gradient from left (transparent) to right (solid). /// + /// The pixel buffer private static void TransparentGradients(Buffer2D pixels) { // topLeft - int left = 0; + const int left = 0; int right = pixels.Width / 2; int top = pixels.Height / 2; int bottom = pixels.Height; int height = (int)Math.Ceiling(pixels.Height / 6f); - var red = Color.Red.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - var green = Color.Green.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - var blue = Color.Blue.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern - - var c = default(TPixel); + Vector4 red = Color.Red.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern + Vector4 green = Color.Green.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern + Vector4 blue = Color.Blue.ToPixel().ToVector4(); // use real color so we can see how it translates in the test pattern for (int x = left; x < right; x++) { - blue.W = red.W = green.W = (float)x / (float)right; + blue.W = red.W = green.W = x / (float)right; - c.FromVector4(red); + TPixel c = TPixel.FromVector4(red); int topBand = top; for (int y = topBand; y < top + height; y++) { pixels[x, y] = c; } - topBand = topBand + height; - c.FromVector4(green); + topBand += height; + c = TPixel.FromVector4(green); for (int y = topBand; y < topBand + height; y++) { pixels[x, y] = c; } - topBand = topBand + height; - c.FromVector4(blue); + topBand += height; + c = TPixel.FromVector4(blue); for (int y = topBand; y < bottom; y++) { pixels[x, y] = c; @@ -190,6 +193,7 @@ public abstract partial class TestImageProvider : IXunitSerializable /// Fills the bottom right quadrant with all the colors producible by converting iterating over a uint and unpacking it. /// A better algorithm could be used but it works /// + /// The pixel buffer. private static void Rainbow(Buffer2D pixels) { int left = pixels.Width / 2; @@ -199,19 +203,14 @@ public abstract partial class TestImageProvider : IXunitSerializable int pixelCount = left * top; uint stepsPerPixel = (uint)(uint.MaxValue / pixelCount); - TPixel c = default; - var t = new Rgba32(0); + Rgba32 t = default; for (int x = left; x < right; x++) { for (int y = top; y < bottom; y++) { t.PackedValue += stepsPerPixel; - var v = t.ToVector4(); - - // v.W = (x - left) / (float)left; - c.FromVector4(v); - pixels[x, y] = c; + pixels[x, y] = TPixel.FromRgba32(t); } } } diff --git a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs index 2243c852d2..78e5c90204 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ImagingTestCaseUtility.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Globalization; using System.Reflection; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.PixelFormats; @@ -62,7 +63,7 @@ public class ImagingTestCaseUtility extension = ".bmp"; } - extension = extension.ToLower(); + extension = extension.ToLower(CultureInfo.InvariantCulture); if (extension[0] != '.') { @@ -86,7 +87,7 @@ public class ImagingTestCaseUtility } } - details = details ?? string.Empty; + details ??= string.Empty; if (details != string.Empty) { details = '_' + details; @@ -277,8 +278,7 @@ public class ImagingTestCaseUtility where TPixel : unmanaged, IPixel { TPixel pixel = img[x, y]; - Rgba64 rgbaPixel = default; - rgbaPixel.FromScaledVector4(pixel.ToScaledVector4()); + Rgba64 rgbaPixel = Rgba64.FromScaledVector4(pixel.ToScaledVector4()); ushort change = (ushort)Math.Round((perChannelChange / 255F) * 65535F); if (rgbaPixel.R + perChannelChange <= 255) @@ -317,7 +317,6 @@ public class ImagingTestCaseUtility rgbaPixel.A -= perChannelChange; } - pixel.FromRgba64(rgbaPixel); - img[x, y] = pixel; + img[x, y] = TPixel.FromRgba64(rgbaPixel); } } diff --git a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs index 3c74b48938..5da12f2643 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestImageExtensions.cs @@ -692,14 +692,14 @@ public static class TestImageExtensions this TestImageProvider provider) where TPixel : unmanaged, IPixel { - var allocator = new TestMemoryAllocator(); + TestMemoryAllocator allocator = new(); provider.Configuration.MemoryAllocator = allocator; return new AllocatorBufferCapacityConfigurator(allocator, Unsafe.SizeOf()); } internal static Image ToGrayscaleImage(this Buffer2D buffer, float scale) { - var image = new Image(buffer.Width, buffer.Height); + Image image = new(buffer.Width, buffer.Height); Assert.True(image.Frames.RootFrame.DangerousTryGetSinglePixelMemory(out Memory pixelMem)); Span pixels = pixelMem.Span; @@ -708,8 +708,7 @@ public static class TestImageExtensions for (int i = 0; i < bufferSpan.Length; i++) { float value = bufferSpan[i] * scale; - var v = new Vector4(value, value, value, 1f); - pixels[i].FromVector4(v); + pixels[i] = Rgba32.FromVector4(new Vector4(value, value, value, 1f)); } return image; @@ -735,7 +734,7 @@ public static class TestImageExtensions Rectangle sourceRectangle = this.SourceRectangle; Configuration configuration = this.Configuration; - var operation = new RowOperation(configuration, sourceRectangle, source.PixelBuffer); + RowOperation operation = new(configuration, sourceRectangle, source.PixelBuffer); ParallelRowIterator.IterateRowIntervals( configuration, diff --git a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs index fb879c7697..f0344e2b9c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestPixel.cs @@ -35,14 +35,9 @@ public class TestPixel : IXunitSerializable public float Alpha { get; set; } - public TPixel AsPixel() - { - var pix = default(TPixel); - pix.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha)); - return pix; - } + public TPixel AsPixel() => TPixel.FromScaledVector4(new Vector4(this.Red, this.Green, this.Blue, this.Alpha)); - internal Span AsSpan() => new(new[] { this.AsPixel() }); + internal Span AsSpan() => new([this.AsPixel()]); public void Deserialize(IXunitSerializationInfo info) { diff --git a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs index 0b792b7fb0..fbdfb9d619 100644 --- a/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs +++ b/tests/ImageSharp.Tests/TestUtilities/TestUtils.cs @@ -19,11 +19,11 @@ namespace SixLabors.ImageSharp.Tests; /// public static class TestUtils { - private static readonly Dictionary ClrTypes2PixelTypes = new Dictionary(); + private static readonly Dictionary ClrTypes2PixelTypes = new(); private static readonly Assembly ImageSharpAssembly = typeof(Rgba32).GetTypeInfo().Assembly; - private static readonly Dictionary PixelTypes2ClrTypes = new Dictionary(); + private static readonly Dictionary PixelTypes2ClrTypes = new(); private static readonly PixelTypes[] AllConcretePixelTypes = GetAllPixelTypes() .Except(new[] { PixelTypes.Undefined, PixelTypes.All }) @@ -52,7 +52,7 @@ public static class TestUtils public static byte[] GetRandomBytes(int length, int seed = 42) { - var rnd = new Random(42); + Random rnd = new(seed); byte[] bytes = new byte[length]; rnd.NextBytes(bytes); return bytes; @@ -60,7 +60,7 @@ public static class TestUtils internal static byte[] FillImageWithRandomBytes(Image image) { - byte[] expected = TestUtils.GetRandomBytes(image.Width * image.Height * 2); + byte[] expected = GetRandomBytes(image.Width * image.Height * 2); image.ProcessPixelRows(accessor => { int cnt = 0; @@ -84,9 +84,6 @@ public static class TestUtils return false; } - var rgb1 = default(Rgb24); - var rgb2 = default(Rgb24); - Buffer2D pixA = a.GetRootFramePixelBuffer(); Buffer2D pixB = b.GetRootFramePixelBuffer(); for (int y = 0; y < a.Height; y++) @@ -105,11 +102,11 @@ public static class TestUtils } else { - Rgba32 rgba = default; - ca.ToRgba32(ref rgba); - rgb1 = rgba.Rgb; - cb.ToRgba32(ref rgba); - rgb2 = rgba.Rgb; + Rgba32 rgba = ca.ToRgba32(); + Rgb24 rgb1 = rgba.Rgb; + + rgba = cb.ToRgba32(); + Rgb24 rgb2 = rgba.Rgb; if (!rgb1.Equals(rgb2)) { @@ -144,7 +141,7 @@ public static class TestUtils return PixelTypes2ClrTypes; } - var result = new Dictionary(); + Dictionary result = new(); foreach (PixelTypes pt in AllConcretePixelTypes) { if (pixelTypes.HasAll(pt)) @@ -167,7 +164,7 @@ public static class TestUtils internal static Color GetColorByName(string colorName) { - var f = (FieldInfo)typeof(Color).GetMember(colorName)[0]; + FieldInfo f = (FieldInfo)typeof(Color).GetMember(colorName)[0]; return (Color)f.GetValue(null); } @@ -188,7 +185,7 @@ public static class TestUtils int width = expected.Width; expected.Mutate(process); - var allocator = new TestMemoryAllocator(); + TestMemoryAllocator allocator = new(); provider.Configuration.MemoryAllocator = allocator; allocator.BufferCapacityInBytes = bufferCapacityInPixelRows * width * Unsafe.SizeOf(); @@ -301,9 +298,9 @@ public static class TestUtils using (Image image0 = provider.GetImage()) { Assert.True(image0.DangerousTryGetSinglePixelMemory(out Memory imageMem)); - var mmg = TestMemoryManager.CreateAsCopyOf(imageMem.Span); + TestMemoryManager mmg = TestMemoryManager.CreateAsCopyOf(imageMem.Span); - using (var image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) + using (Image image1 = Image.WrapMemory(mmg.Memory, image0.Width, image0.Height)) { image1.Mutate(process); image1.DebugSave( @@ -353,7 +350,7 @@ public static class TestUtils using (Image image = provider.GetImage()) { - var bounds = new Rectangle(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2); + Rectangle bounds = new(image.Width / 4, image.Width / 4, image.Width / 2, image.Height / 2); image.Mutate(x => process(x, bounds)); image.DebugSave(provider, testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName); image.CompareToReferenceOutput(comparer, provider, testOutputDetails: testOutputDetails, appendPixelTypeToFileName: appendPixelTypeToFileName); @@ -384,7 +381,7 @@ public static class TestUtils if (property is null) { - throw new Exception($"No resampler named '{name}"); + throw new InvalidOperationException($"No resampler named '{name}"); } return (IResampler)property.GetValue(null); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs index 3dceaf2524..2f5291131c 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestImageProviderTests.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Collections.Concurrent; -using SixLabors.ImageSharp.Advanced; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; @@ -302,12 +301,11 @@ public class TestImageProviderTests Assert.Equal(20, img.Height); Buffer2D pixels = img.GetRootFramePixelBuffer(); - Rgba32 rgba = default; for (int y = 0; y < pixels.Height; y++) { for (int x = 0; x < pixels.Width; x++) { - pixels[x, y].ToRgba32(ref rgba); + Rgba32 rgba = pixels[x, y].ToRgba32(); Assert.Equal(255, rgba.R); Assert.Equal(100, rgba.G); diff --git a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs index 33ee68068f..46fb7159e8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs +++ b/tests/ImageSharp.Tests/TestUtilities/Tests/TestUtilityExtensionsTests.cs @@ -21,20 +21,17 @@ public class TestUtilityExtensionsTests public static Image CreateTestImage() where TPixel : unmanaged, IPixel { - var image = new Image(10, 10); + Image image = new(10, 10); Buffer2D pixels = image.GetRootFramePixelBuffer(); for (int i = 0; i < 10; i++) { for (int j = 0; j < 10; j++) { - var v = new Vector4(i, j, 0, 1); + Vector4 v = new(i, j, 0, 1); v /= 10; - var color = default(TPixel); - color.FromVector4(v); - - pixels[i, j] = color; + pixels[i, j] = TPixel.FromVector4(v); } } From 8af75fe0d4ab187e7de9ca49507ec84d99eb01f2 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 21 Jan 2024 21:42:33 +1000 Subject: [PATCH 132/219] Restore GetPixelTypeInfo --- src/ImageSharp/PixelFormats/IPixel.cs | 13 ++++++------- tests/ImageSharp.Tests/ImageSharp.Tests.csproj | 4 ---- tests/ImageSharp.Tests/Issues/Issue594.cs | 12 +++--------- .../PixelOperations/PixelOperationsTests.cs | 4 ++-- .../TestUtilities/ApproximateFloatComparer.cs | 9 --------- 5 files changed, 11 insertions(+), 31 deletions(-) diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index f473ce248e..23b18354a6 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -22,13 +22,6 @@ public interface IPixel : IPixel, IEquatable PixelOperations CreatePixelOperations(); #pragma warning disable CA1000 // Do not declare static members on generic types - - /// - /// Gets the pixel type information. - /// - /// The . - static abstract PixelTypeInfo GetPixelTypeInfo(); - /// /// Initializes the pixel instance from a generic scaled . /// @@ -141,6 +134,12 @@ public interface IPixel : IPixel, IEquatable /// public interface IPixel { + /// + /// Gets the pixel type information. + /// + /// The . + static abstract PixelTypeInfo GetPixelTypeInfo(); + /// /// Convert the pixel instance into representation. /// diff --git a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj index e0c65475af..a389c8ab8c 100644 --- a/tests/ImageSharp.Tests/ImageSharp.Tests.csproj +++ b/tests/ImageSharp.Tests/ImageSharp.Tests.csproj @@ -80,9 +80,5 @@ - - - - diff --git a/tests/ImageSharp.Tests/Issues/Issue594.cs b/tests/ImageSharp.Tests/Issues/Issue594.cs index 23a3913fae..7f976a3731 100644 --- a/tests/ImageSharp.Tests/Issues/Issue594.cs +++ b/tests/ImageSharp.Tests/Issues/Issue594.cs @@ -8,9 +8,7 @@ namespace SixLabors.ImageSharp.Tests.Issues; public class Issue594 { - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact] // (Skip = "Skipped because of issue #594")] + [Fact] public void NormalizedByte4Test() { // Test PackedValue @@ -50,9 +48,7 @@ public class Issue594 Assert.Equal(958796544U, new NormalizedByte4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); } - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact] //(Skip = "Skipped because of issue #594")] + [Fact] public void NormalizedShort4Test() { // Test PackedValue @@ -87,9 +83,7 @@ public class Issue594 Assert.Equal(4150390751449251866UL, new NormalizedShort4(0.0008f, 0.15f, 0.30f, 0.45f).PackedValue); } - // This test fails for unknown reason in Release mode on linux and is meant to help reproducing the issue - // see https://github.com/SixLabors/ImageSharp/issues/594 - [Fact] // (Skip = "Skipped because of issue #594")] + [Fact] public void Short4Test() { // Test the limits. diff --git a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs index b9d9b695ae..68c282d8a1 100644 --- a/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs +++ b/tests/ImageSharp.Tests/PixelFormats/PixelOperations/PixelOperationsTests.cs @@ -1216,7 +1216,7 @@ public abstract class PixelOperationsTests : MeasureFixture for (int i = 0; i < count; i++) { - Assert.Equal((IPixel)expected[i], (IPixel)actual[i], comparer); + Assert.Equal(((IPixel)expected[i]).ToScaledVector4(), ((IPixel)actual[i]).ToScaledVector4(), comparer); } } else @@ -1231,7 +1231,7 @@ public abstract class PixelOperationsTests : MeasureFixture } } - // TODO: We really need a PixelTypeInfo.BitsPerComponent property!! + // TODO: Figure out a means to use PixelTypeInfo here. private static bool IsComplexPixel() => default(TDest) switch { HalfSingle or HalfVector2 or L16 or La32 or NormalizedShort2 or Rg32 or Short2 => true, diff --git a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs index e35f36feec..21ac6966b8 100644 --- a/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/ApproximateFloatComparer.cs @@ -4,7 +4,6 @@ using System.Diagnostics.CodeAnalysis; using System.Numerics; using System.Runtime.Intrinsics; -using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Tests; @@ -14,7 +13,6 @@ namespace SixLabors.ImageSharp.Tests; internal readonly struct ApproximateFloatComparer : IEqualityComparer, IEqualityComparer, - IEqualityComparer, IEqualityComparer, IEqualityComparer, IEqualityComparer> @@ -47,13 +45,6 @@ internal readonly struct ApproximateFloatComparer : public int GetHashCode(Vector2 obj) => obj.GetHashCode(); - /// - public bool Equals(IPixel x, IPixel y) - => this.Equals(x.ToScaledVector4(), y.ToScaledVector4()); - - public int GetHashCode(IPixel obj) - => obj.ToScaledVector4().GetHashCode(); - /// public bool Equals(Vector4 x, Vector4 y) => this.Equals(x.X, y.X) From 2de4f2c54ed0bcadc0c7c305a55d8463a31ba8fd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 21 Jan 2024 22:04:47 +1000 Subject: [PATCH 133/219] Update refs --- .editorconfig | 2 ++ shared-infrastructure | 2 +- src/ImageSharp.ruleset | 3 --- 3 files changed, 3 insertions(+), 4 deletions(-) diff --git a/.editorconfig b/.editorconfig index 2e3045fb17..c28089d720 100644 --- a/.editorconfig +++ b/.editorconfig @@ -172,6 +172,8 @@ dotnet_diagnostic.IDE0063.severity = suggestion csharp_using_directive_placement = outside_namespace:warning # Modifier preferences csharp_prefer_static_local_function = true:warning +# Primary constructor preferences +csharp_style_prefer_primary_constructors = false:none ########################################## # Unnecessary Code Rules diff --git a/shared-infrastructure b/shared-infrastructure index d65232bbbf..1dbfb576c8 160000 --- a/shared-infrastructure +++ b/shared-infrastructure @@ -1 +1 @@ -Subproject commit d65232bbbfe55a9a153b4058139dda5230e6eb4f +Subproject commit 1dbfb576c83507645265c79e03369b66cdc0379f diff --git a/src/ImageSharp.ruleset b/src/ImageSharp.ruleset index 72e0cd1b0f..b609890200 100644 --- a/src/ImageSharp.ruleset +++ b/src/ImageSharp.ruleset @@ -1,7 +1,4 @@  - - - \ No newline at end of file From 6580494b5aff13480f81ed623b14b5c3c1eeba62 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 22 Jan 2024 09:43:09 +0000 Subject: [PATCH 134/219] Bump actions/cache from 3 to 4 Bumps [actions/cache](https://github.com/actions/cache) from 3 to 4. - [Release notes](https://github.com/actions/cache/releases) - [Changelog](https://github.com/actions/cache/blob/main/RELEASES.md) - [Commits](https://github.com/actions/cache/compare/v3...v4) --- updated-dependencies: - dependency-name: actions/cache dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-and-test.yml | 6 +++--- .github/workflows/code-coverage.yml | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 75bcb8a256..57488a1d0a 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -67,7 +67,7 @@ jobs: run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - name: Git Setup LFS Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: lfs-cache with: path: .git/lfs @@ -80,7 +80,7 @@ jobs: uses: NuGet/setup-nuget@v1 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget @@ -162,7 +162,7 @@ jobs: uses: NuGet/setup-nuget@v1 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 62b6477ee6..f9d2da0c8b 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -34,7 +34,7 @@ jobs: run: git lfs ls-files -l | cut -d' ' -f1 | sort > .lfs-assets-id - name: Git Setup LFS Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: lfs-cache with: path: .git/lfs @@ -47,7 +47,7 @@ jobs: uses: NuGet/setup-nuget@v1 - name: NuGet Setup Cache - uses: actions/cache@v3 + uses: actions/cache@v4 id: nuget-cache with: path: ~/.nuget From 7b93ee74d5b881daa51b5c8c6dc9e657ba14f83b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 23 Jan 2024 23:26:23 +1000 Subject: [PATCH 135/219] Update benchmarks --- .../General/PixelConversion/ITestPixel.cs | 8 +- .../PixelConversion_ConvertFromRgba32.cs | 184 +++++++++++------- .../PixelConversion_ConvertFromVector4.cs | 37 ---- .../General/PixelConversion/TestArgb.cs | 95 +++++---- .../General/PixelConversion/TestRgba.cs | 69 ++++--- .../General/PixelConversion/TestRgbaVector.cs | 51 +++++ 6 files changed, 266 insertions(+), 178 deletions(-) create mode 100644 tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs index 8820406af6..82f0da5052 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/ITestPixel.cs @@ -11,19 +11,23 @@ public interface ITestPixel { void FromRgba32(Rgba32 source); + static abstract T StaticFromRgba32(Rgba32 source); + void FromRgba32(ref Rgba32 source); void FromBytes(byte r, byte g, byte b, byte a); void FromVector4(Vector4 source); + static abstract T StaticFromVector4(Vector4 source); + void FromVector4(ref Vector4 source); Rgba32 ToRgba32(); - void CopyToRgba32(ref Rgba32 dest); + void CopyToRgba32(ref Rgba32 destination); Vector4 ToVector4(); - void CopyToVector4(ref Vector4 dest); + void CopyToVector4(ref Vector4 destination); } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs index 479079a80c..1d83b94dc8 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromRgba32.cs @@ -13,25 +13,25 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public abstract class PixelConversion_ConvertFromRgba32 { - internal struct ConversionRunner + internal readonly struct ConversionRunner where T : struct, ITestPixel { - public readonly T[] Dest; + public readonly T[] Destination; public readonly Rgba32[] Source; public ConversionRunner(int count) { - this.Dest = new T[count]; + this.Destination = new T[count]; this.Source = new Rgba32[count]; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByRefConversion() + public readonly void RunByRefConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -41,11 +41,11 @@ public abstract class PixelConversion_ConvertFromRgba32 } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunByValConversion() + public readonly void RunByValConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -55,11 +55,25 @@ public abstract class PixelConversion_ConvertFromRgba32 } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void RunFromBytesConversion() + public readonly void RunStaticByValConversion() { - int count = this.Dest.Length; + int count = this.Destination.Length; - ref T destBaseRef = ref this.Dest[0]; + ref T destBaseRef = ref this.Destination[0]; + ref Rgba32 sourceBaseRef = ref this.Source[0]; + + for (nuint i = 0; i < (uint)count; i++) + { + Unsafe.Add(ref destBaseRef, i) = T.StaticFromRgba32(Unsafe.Add(ref sourceBaseRef, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void RunFromBytesConversion() + { + int count = this.Destination.Length; + + ref T destBaseRef = ref this.Destination[0]; ref Rgba32 sourceBaseRef = ref this.Source[0]; for (nuint i = 0; i < (uint)count; i++) @@ -74,6 +88,8 @@ public abstract class PixelConversion_ConvertFromRgba32 internal ConversionRunner PermutedRunnerRgbaToArgb; + internal ConversionRunner RunnerRgbaToRgbaVector; + [Params(256, 2048)] public int Count { get; set; } @@ -82,34 +98,29 @@ public abstract class PixelConversion_ConvertFromRgba32 { this.CompatibleMemLayoutRunner = new ConversionRunner(this.Count); this.PermutedRunnerRgbaToArgb = new ConversionRunner(this.Count); + this.RunnerRgbaToRgbaVector = new ConversionRunner(this.Count); } } public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_ConvertFromRgba32 { [Benchmark(Baseline = true)] - public void ByRef() - { - this.CompatibleMemLayoutRunner.RunByRefConversion(); - } + public void ByRef() => this.CompatibleMemLayoutRunner.RunByRefConversion(); [Benchmark] - public void ByVal() - { - this.CompatibleMemLayoutRunner.RunByValConversion(); - } + public void ByVal() => this.CompatibleMemLayoutRunner.RunByValConversion(); [Benchmark] - public void FromBytes() - { - this.CompatibleMemLayoutRunner.RunFromBytesConversion(); - } + public void StaticByVal() => this.CompatibleMemLayoutRunner.RunStaticByValConversion(); + + [Benchmark] + public void FromBytes() => this.CompatibleMemLayoutRunner.RunFromBytesConversion(); [Benchmark] public void Inline() { ref Rgba32 sBase = ref this.CompatibleMemLayoutRunner.Source[0]; - ref Rgba32 dBase = ref Unsafe.As(ref this.CompatibleMemLayoutRunner.Dest[0]); + ref Rgba32 dBase = ref Unsafe.As(ref this.CompatibleMemLayoutRunner.Destination[0]); for (nuint i = 0; i < (uint)this.Count; i++) { @@ -120,50 +131,46 @@ public class PixelConversion_ConvertFromRgba32_Compatible : PixelConversion_Conv /* BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores - .NET SDK 8.0.100 - [Host] : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2 - DefaultJob : .NET 8.0.0 (8.0.23.53103), X64 RyuJIT AVX2 - - - | Method | Count | Mean | Error | StdDev | Ratio | - |---------- |------ |-----------:|--------:|--------:|------:| - | ByRef | 256 | 102.5 ns | 0.44 ns | 0.39 ns | 1.00 | - | ByVal | 256 | 102.2 ns | 0.30 ns | 0.25 ns | 1.00 | - | FromBytes | 256 | 200.5 ns | 1.01 ns | 0.90 ns | 1.96 | - | Inline | 256 | 107.0 ns | 0.90 ns | 0.84 ns | 1.04 | - | | | | | | | - | ByRef | 2048 | 770.8 ns | 3.22 ns | 2.86 ns | 1.00 | - | ByVal | 2048 | 770.3 ns | 2.05 ns | 1.92 ns | 1.00 | - | FromBytes | 2048 | 1,546.8 ns | 7.51 ns | 6.66 ns | 2.01 | - | Inline | 2048 | 797.6 ns | 2.90 ns | 2.26 ns | 1.03 | + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | + |------------ |------ |-----------:|--------:|--------:|------:| + | ByRef | 256 | 103.4 ns | 0.52 ns | 0.46 ns | 1.00 | + | ByVal | 256 | 103.3 ns | 1.48 ns | 1.38 ns | 1.00 | + | StaticByVal | 256 | 104.0 ns | 0.36 ns | 0.30 ns | 1.01 | + | FromBytes | 256 | 201.8 ns | 1.30 ns | 1.15 ns | 1.95 | + | Inline | 256 | 106.6 ns | 0.40 ns | 0.34 ns | 1.03 | + | | | | | | | + | ByRef | 2048 | 771.5 ns | 3.68 ns | 3.27 ns | 1.00 | + | ByVal | 2048 | 769.7 ns | 3.39 ns | 2.83 ns | 1.00 | + | StaticByVal | 2048 | 773.2 ns | 3.95 ns | 3.50 ns | 1.00 | + | FromBytes | 2048 | 1,555.3 ns | 9.24 ns | 8.19 ns | 2.02 | + | Inline | 2048 | 799.5 ns | 5.91 ns | 4.93 ns | 1.04 | */ } public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConversion_ConvertFromRgba32 { [Benchmark(Baseline = true)] - public void ByRef() - { - this.PermutedRunnerRgbaToArgb.RunByRefConversion(); - } + public void ByRef() => this.PermutedRunnerRgbaToArgb.RunByRefConversion(); [Benchmark] - public void ByVal() - { - this.PermutedRunnerRgbaToArgb.RunByValConversion(); - } + public void ByVal() => this.PermutedRunnerRgbaToArgb.RunByValConversion(); [Benchmark] - public void FromBytes() - { - this.PermutedRunnerRgbaToArgb.RunFromBytesConversion(); - } + public void StaticByVal() => this.PermutedRunnerRgbaToArgb.RunStaticByValConversion(); + + [Benchmark] + public void FromBytes() => this.PermutedRunnerRgbaToArgb.RunFromBytesConversion(); [Benchmark] public void InlineShuffle() { ref Rgba32 sBase = ref this.PermutedRunnerRgbaToArgb.Source[0]; - ref TestArgb dBase = ref this.PermutedRunnerRgbaToArgb.Dest[0]; + ref TestArgb dBase = ref this.PermutedRunnerRgbaToArgb.Destination[0]; for (nuint i = 0; i < (uint)this.Count; i++) { @@ -181,25 +188,64 @@ public class PixelConversion_ConvertFromRgba32_Permuted_RgbaToArgb : PixelConver public void PixelConverter_Rgba32_ToArgb32() { Span source = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Source); - Span dest = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Dest); + Span dest = MemoryMarshal.Cast(this.PermutedRunnerRgbaToArgb.Destination); PixelConverter.FromRgba32.ToArgb32(source, dest); } /* - RESULTS: - | Method | Count | Mean | Error | StdDev | Median | Ratio | RatioSD | - |------------------------------- |------ |------------:|----------:|----------:|------------:|------:|--------:| - | ByRef | 256 | 288.84 ns | 19.601 ns | 52.319 ns | 268.10 ns | 1.00 | 0.00 | - | ByVal | 256 | 267.97 ns | 1.831 ns | 1.713 ns | 267.85 ns | 0.77 | 0.18 | - | FromBytes | 256 | 266.81 ns | 2.427 ns | 2.270 ns | 266.47 ns | 0.76 | 0.18 | - | InlineShuffle | 256 | 291.41 ns | 5.820 ns | 5.444 ns | 290.17 ns | 0.83 | 0.19 | - | PixelConverter_Rgba32_ToArgb32 | 256 | 38.62 ns | 0.431 ns | 0.403 ns | 38.68 ns | 0.11 | 0.03 | - | | | | | | | | | - | ByRef | 2048 | 2,197.69 ns | 15.826 ns | 14.804 ns | 2,197.25 ns | 1.00 | 0.00 | - | ByVal | 2048 | 2,226.81 ns | 44.266 ns | 62.054 ns | 2,197.17 ns | 1.03 | 0.04 | - | FromBytes | 2048 | 2,181.35 ns | 18.033 ns | 16.868 ns | 2,185.97 ns | 0.99 | 0.01 | - | InlineShuffle | 2048 | 2,233.10 ns | 27.673 ns | 24.531 ns | 2,229.78 ns | 1.02 | 0.01 | - | PixelConverter_Rgba32_ToArgb32 | 2048 | 139.90 ns | 2.152 ns | 3.825 ns | 138.70 ns | 0.06 | 0.00 | + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | + |------------------------------- |------ |------------:|----------:|---------:|------:|--------:| + | ByRef | 256 | 203.48 ns | 3.318 ns | 3.104 ns | 1.00 | 0.00 | + | ByVal | 256 | 201.46 ns | 2.242 ns | 1.872 ns | 0.99 | 0.02 | + | StaticByVal | 256 | 201.45 ns | 0.791 ns | 0.701 ns | 0.99 | 0.02 | + | FromBytes | 256 | 200.76 ns | 1.365 ns | 1.140 ns | 0.99 | 0.01 | + | InlineShuffle | 256 | 221.65 ns | 2.104 ns | 1.968 ns | 1.09 | 0.02 | + | PixelConverter_Rgba32_ToArgb32 | 256 | 26.23 ns | 0.277 ns | 0.231 ns | 0.13 | 0.00 | + | | | | | | | | + | ByRef | 2048 | 1,561.54 ns | 11.208 ns | 8.751 ns | 1.00 | 0.00 | + | ByVal | 2048 | 1,554.26 ns | 9.607 ns | 8.517 ns | 1.00 | 0.01 | + | StaticByVal | 2048 | 1,562.48 ns | 8.937 ns | 8.360 ns | 1.00 | 0.01 | + | FromBytes | 2048 | 1,552.68 ns | 7.445 ns | 5.812 ns | 0.99 | 0.01 | + | InlineShuffle | 2048 | 1,711.28 ns | 7.559 ns | 6.312 ns | 1.10 | 0.01 | + | PixelConverter_Rgba32_ToArgb32 | 2048 | 94.43 ns | 0.363 ns | 0.322 ns | 0.06 | 0.00 | + */ +} + +public class PixelConversion_ConvertFromRgba32_RgbaToRgbaVector : PixelConversion_ConvertFromRgba32 +{ + [Benchmark(Baseline = true)] + public void ByRef() => this.RunnerRgbaToRgbaVector.RunByRefConversion(); + + [Benchmark] + public void ByVal() => this.RunnerRgbaToRgbaVector.RunByValConversion(); + + [Benchmark] + public void StaticByVal() => this.RunnerRgbaToRgbaVector.RunStaticByValConversion(); + + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3007/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + DefaultJob : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | + |------------ |------ |-----------:|---------:|---------:|------:|--------:| + | ByRef | 256 | 448.5 ns | 4.86 ns | 4.06 ns | 1.00 | 0.00 | + | ByVal | 256 | 447.0 ns | 1.55 ns | 1.21 ns | 1.00 | 0.01 | + | StaticByVal | 256 | 447.4 ns | 1.67 ns | 1.30 ns | 1.00 | 0.01 | + | | | | | | | | + | ByRef | 2048 | 3,577.7 ns | 53.80 ns | 47.69 ns | 1.00 | 0.00 | + | ByVal | 2048 | 3,590.5 ns | 43.59 ns | 36.40 ns | 1.00 | 0.02 | + | StaticByVal | 2048 | 3,604.6 ns | 16.19 ns | 14.36 ns | 1.01 | 0.01 | */ } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs index dd85d06417..57f79ba1f3 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/PixelConversion_ConvertFromVector4.cs @@ -13,43 +13,6 @@ namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; public class PixelConversion_ConvertFromVector4 { - [StructLayout(LayoutKind.Sequential)] - private struct TestRgbaVector : ITestPixel - { - private Vector4 v; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) - { - this.v = p; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) - { - this.v = p; - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() => this.v; - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) - { - dest = this.v; - } - - public void FromRgba32(Rgba32 source) => throw new System.NotImplementedException(); - - public void FromRgba32(ref Rgba32 source) => throw new System.NotImplementedException(); - - public void FromBytes(byte r, byte g, byte b, byte a) => throw new System.NotImplementedException(); - - public Rgba32 ToRgba32() => throw new System.NotImplementedException(); - - public void CopyToRgba32(ref Rgba32 dest) => throw new System.NotImplementedException(); - } - private struct ConversionRunner where T : struct, ITestPixel { diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs index 84698a0e19..21bef5a156 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestArgb.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; @@ -16,26 +17,20 @@ public struct TestArgb : ITestPixel public byte G; public byte B; - [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 p) - { - this.R = p.R; - this.G = p.G; - this.B = p.B; - this.A = p.A; - } + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 p) + private TestArgb(Rgba32 source) { - this.R = p.R; - this.G = p.G; - this.B = p.B; - this.A = p.A; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromBytes(byte r, byte g, byte b, byte a) + private TestArgb(byte r, byte g, byte b, byte a) { this.R = r; this.G = g; @@ -44,50 +39,70 @@ public struct TestArgb : ITestPixel } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(Vector4 p) + public void FromRgba32(Rgba32 source) { - this.R = (byte)p.X; - this.G = (byte)p.Y; - this.B = (byte)p.Z; - this.A = (byte)p.W; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromVector4(ref Vector4 p) + public void FromRgba32(ref Rgba32 source) { - this.R = (byte)p.X; - this.G = (byte)p.Y; - this.B = (byte)p.Z; - this.A = (byte)p.W; + this.R = source.R; + this.G = source.G; + this.B = source.B; + this.A = source.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return new Rgba32(this.R, this.G, this.B, this.A); - } + public static TestArgb StaticFromRgba32(Rgba32 source) => new(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) + public void FromBytes(byte r, byte g, byte b, byte a) { - dest.R = this.R; - dest.G = this.G; - dest.B = this.B; - dest.A = this.A; + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() + public void FromVector4(Vector4 source) => this = Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestArgb StaticFromVector4(Vector4 source) => Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 source) => this = Pack(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => new(this.R, this.G, this.B, this.A); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToRgba32(ref Rgba32 destination) { - return new Vector4(this.R, this.G, this.B, this.A); + destination.R = this.R; + destination.G = this.G; + destination.B = this.B; + destination.A = this.A; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.ToVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TestArgb Pack(Vector4 vector) { - dest.X = this.R; - dest.Y = this.G; - dest.Z = this.B; - dest.W = this.A; + vector *= MaxBytes; + vector += Half; + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs index 76449c9d95..1499fb7d3d 100644 --- a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgba.cs @@ -4,6 +4,7 @@ using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; @@ -16,17 +17,29 @@ public struct TestRgba : ITestPixel public byte B; public byte A; + private static readonly Vector4 MaxBytes = Vector128.Create(255f).AsVector4(); + private static readonly Vector4 Half = Vector128.Create(.5f).AsVector4(); + [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(Rgba32 source) + private TestRgba(byte r, byte g, byte b, byte a) { - this = Unsafe.As(ref source); + this.R = r; + this.G = g; + this.B = b; + this.A = a; } [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void FromRgba32(ref Rgba32 source) - { - this = Unsafe.As(ref source); - } + private TestRgba(Rgba32 source) => this = Unsafe.As(ref source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) => this = Unsafe.As(ref source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgba StaticFromRgba32(Rgba32 source) => new(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) => this = Unsafe.As(ref source); [MethodImpl(MethodImplOptions.AggressiveInlining)] public void FromBytes(byte r, byte g, byte b, byte a) @@ -37,39 +50,35 @@ public struct TestRgba : ITestPixel this.A = a; } - public void FromVector4(Vector4 source) - { - throw new System.NotImplementedException(); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 source) => this = Pack(source); - public void FromVector4(ref Vector4 source) - { - throw new System.NotImplementedException(); - } + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgba StaticFromVector4(Vector4 source) => Pack(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Rgba32 ToRgba32() - { - return Unsafe.As(ref this); - } + public void FromVector4(ref Vector4 source) => this = Pack(source); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToRgba32(ref Rgba32 dest) - { - dest = Unsafe.As(ref this); - } + public Rgba32 ToRgba32() => Unsafe.As(ref this); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public Vector4 ToVector4() - { - return new Vector4(this.R, this.G, this.B, this.A) * new Vector4(1f / 255f); - } + public void CopyToRgba32(ref Rgba32 destination) => destination = Unsafe.As(ref this); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => new Vector4(this.R, this.G, this.B, this.A) / MaxBytes; [MethodImpl(MethodImplOptions.AggressiveInlining)] - public void CopyToVector4(ref Vector4 dest) + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.ToVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static TestRgba Pack(Vector4 vector) { - var tmp = new Vector4(this.R, this.G, this.B, this.A); - tmp *= new Vector4(1f / 255f); - dest = tmp; + vector *= MaxBytes; + vector += Half; + vector = Numerics.Clamp(vector, Vector4.Zero, MaxBytes); + + Vector128 result = Vector128.ConvertToInt32(vector.AsVector128()).AsByte(); + return new(result.GetElement(0), result.GetElement(4), result.GetElement(8), result.GetElement(12)); } } diff --git a/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs new file mode 100644 index 0000000000..07790ae998 --- /dev/null +++ b/tests/ImageSharp.Benchmarks/General/PixelConversion/TestRgbaVector.cs @@ -0,0 +1,51 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Numerics; +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; +using SixLabors.ImageSharp.PixelFormats; + +namespace SixLabors.ImageSharp.Benchmarks.General.PixelConversion; + +[StructLayout(LayoutKind.Sequential)] +public struct TestRgbaVector : ITestPixel +{ + private Vector4 v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private TestRgbaVector(Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgbaVector StaticFromVector4(Vector4 source) => new(source); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromVector4(ref Vector4 source) => this.v = source; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Vector4 ToVector4() => this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToVector4(ref Vector4 destination) => destination = this.v; + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(Rgba32 source) => this.v = source.ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static TestRgbaVector StaticFromRgba32(Rgba32 source) => new(source.ToScaledVector4()); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromRgba32(ref Rgba32 source) => this.v = source.ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public void FromBytes(byte r, byte g, byte b, byte a) => this.v = new Rgba32(r, g, b, a).ToScaledVector4(); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.v); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public readonly void CopyToRgba32(ref Rgba32 destination) => destination = Rgba32.FromScaledVector4(this.v); +} From 3a3ff89ec48d9df4150429099a5ec91db82708b0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 23 Jan 2024 23:48:30 +1000 Subject: [PATCH 136/219] Make CreatePixelOperations static --- src/ImageSharp/PixelFormats/IPixel.cs | 4 ++-- src/ImageSharp/PixelFormats/PixelImplementations/A8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs | 2 +- .../PixelFormats/PixelImplementations/HalfSingle.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector2.cs | 2 +- .../PixelFormats/PixelImplementations/HalfVector4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/L8.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La16.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/La32.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedByte4.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort2.cs | 2 +- .../PixelFormats/PixelImplementations/NormalizedShort4.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs | 2 +- .../PixelFormats/PixelImplementations/Rgba1010102.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs | 2 +- .../PixelFormats/PixelImplementations/RgbaVector.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs | 2 +- src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs | 2 +- src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs | 2 +- tests/ImageSharp.Tests/Color/RgbaDouble.cs | 2 +- tests/ImageSharp.Tests/TestFormat.cs | 2 +- 33 files changed, 34 insertions(+), 34 deletions(-) diff --git a/src/ImageSharp/PixelFormats/IPixel.cs b/src/ImageSharp/PixelFormats/IPixel.cs index 23b18354a6..adf386614d 100644 --- a/src/ImageSharp/PixelFormats/IPixel.cs +++ b/src/ImageSharp/PixelFormats/IPixel.cs @@ -14,14 +14,14 @@ namespace SixLabors.ImageSharp.PixelFormats; public interface IPixel : IPixel, IEquatable where TSelf : unmanaged, IPixel { +#pragma warning disable CA1000 // Do not declare static members on generic types /// /// Creates a instance for this pixel type. /// This method is not intended to be consumed directly. Use instead. /// /// The instance. - PixelOperations CreatePixelOperations(); + static abstract PixelOperations CreatePixelOperations(); -#pragma warning disable CA1000 // Do not declare static members on generic types /// /// Initializes the pixel instance from a generic scaled . /// diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs index fdf7ccb407..94fbf7eb76 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/A8.cs @@ -75,7 +75,7 @@ public partial struct A8 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs index 65354c807f..453a392289 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Abgr32.cs @@ -192,7 +192,7 @@ public partial struct Abgr32 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs index 50557880a0..f8608ecc52 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Argb32.cs @@ -185,7 +185,7 @@ public partial struct Argb32 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs index 12e6736b71..a860edc567 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr24.cs @@ -95,7 +95,7 @@ public partial struct Bgr24 : IPixel PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs index fe26bb8fd1..87055bf22d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgr565.cs @@ -73,7 +73,7 @@ public partial struct Bgr565(Vector3 vector) : IPixel, IPackedVector - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// public readonly Rgba32 ToRgba32() => Rgba32.FromScaledVector4(this.ToScaledVector4()); diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs index fc5d55e64c..0fe7e4cc2c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra32.cs @@ -134,7 +134,7 @@ public partial struct Bgra32 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs index 4c89d8e944..55971210c3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra4444.cs @@ -86,7 +86,7 @@ public partial struct Bgra4444 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs index fde937fb54..4c94dea5f1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Bgra5551.cs @@ -84,7 +84,7 @@ public partial struct Bgra5551 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs index 8b4384ff7f..680a7ee0bd 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Byte4.cs @@ -86,7 +86,7 @@ public partial struct Byte4 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs index 45cc061ae4..888d992d8c 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfSingle.cs @@ -70,7 +70,7 @@ public partial struct HalfSingle : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs index 1fd3125231..861a8480aa 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector2.cs @@ -82,7 +82,7 @@ public partial struct HalfVector2 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs index 4741bcf9e4..d0b57d788f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/HalfVector4.cs @@ -87,7 +87,7 @@ public partial struct HalfVector4 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs index 41578a6f60..2b5241b0bc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L16.cs @@ -75,7 +75,7 @@ public partial struct L16 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs index 90731f6e97..5d733bdbb3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/L8.cs @@ -77,7 +77,7 @@ public partial struct L8 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs index 948f0b1443..69ca662187 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La16.cs @@ -104,7 +104,7 @@ public partial struct La16 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs index 0381973d9c..1886ef39a1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/La32.cs @@ -101,7 +101,7 @@ public partial struct La32 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs index e901adc9e5..9551d7242f 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte2.cs @@ -85,7 +85,7 @@ public partial struct NormalizedByte2 : IPixel, IPackedVector - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs index 1202801abd..1fb386725a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedByte4.cs @@ -92,7 +92,7 @@ public partial struct NormalizedByte4 : IPixel, IPackedVector - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs index e15cdafa74..a17868f6df 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort2.cs @@ -87,7 +87,7 @@ public partial struct NormalizedShort2 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs index f692f73b24..2b33fec27a 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/NormalizedShort4.cs @@ -93,7 +93,7 @@ public partial struct NormalizedShort4 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs index 0dea025122..e7c97269e1 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rg32.cs @@ -82,7 +82,7 @@ public partial struct Rg32 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs index a4445bd716..ac855d47dc 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb24.cs @@ -104,7 +104,7 @@ public partial struct Rgb24 : IPixel PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs index d4f1cabb2c..e822d2abc8 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgb48.cs @@ -89,7 +89,7 @@ public partial struct Rgb48 : IPixel PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs index 0f7be17740..cdee22964d 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba1010102.cs @@ -84,7 +84,7 @@ public partial struct Rgba1010102 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs index 8b5779a532..fc347c1665 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba32.cs @@ -288,7 +288,7 @@ public partial struct Rgba32 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs index 73629461b2..27c4752e10 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Rgba64.cs @@ -210,7 +210,7 @@ public partial struct Rgba64 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs index 60555ad95d..a27cffad83 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/RgbaVector.cs @@ -104,7 +104,7 @@ public partial struct RgbaVector : IPixel PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs index 043599c366..403d3fbea3 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short2.cs @@ -90,7 +90,7 @@ public partial struct Short2 : IPixel, IPackedVector PixelAlphaRepresentation.None); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs index df43703cb7..b6cece2bef 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/Short4.cs @@ -97,7 +97,7 @@ public partial struct Short4 : IPixel, IPackedVector PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new PixelOperations(); + public static PixelOperations CreatePixelOperations() => new PixelOperations(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs index 174b3fae18..c769b389d2 100644 --- a/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs +++ b/src/ImageSharp/PixelFormats/PixelOperations{TPixel}.cs @@ -17,7 +17,7 @@ namespace SixLabors.ImageSharp.PixelFormats; public partial class PixelOperations where TPixel : unmanaged, IPixel { - private static readonly Lazy> LazyInstance = new(() => default(TPixel).CreatePixelOperations(), true); + private static readonly Lazy> LazyInstance = new(TPixel.CreatePixelOperations, true); /// /// Gets the global instance for the pixel type diff --git a/tests/ImageSharp.Tests/Color/RgbaDouble.cs b/tests/ImageSharp.Tests/Color/RgbaDouble.cs index bb86729416..9a751e8791 100644 --- a/tests/ImageSharp.Tests/Color/RgbaDouble.cs +++ b/tests/ImageSharp.Tests/Color/RgbaDouble.cs @@ -104,7 +104,7 @@ public struct RgbaDouble : IPixel PixelAlphaRepresentation.Unassociated); /// - public readonly PixelOperations CreatePixelOperations() => new(); + public static PixelOperations CreatePixelOperations() => new(); /// [MethodImpl(MethodImplOptions.AggressiveInlining)] diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 89e2a11a90..10211f386c 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -275,7 +275,7 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat PixelColorType.Red | PixelColorType.Green, PixelAlphaRepresentation.None); - public PixelOperations CreatePixelOperations() => new(); + public static PixelOperations CreatePixelOperations() => new(); public static TestPixelForAgnosticDecode FromScaledVector4(Vector4 vector) => default; From 51272021290112a51812c53eefb9d0d4124b13ff Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Tue, 23 Jan 2024 17:00:34 +0100 Subject: [PATCH 137/219] pr comment fix --- src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs | 2 +- src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs | 2 +- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 8 ++++---- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index e11923ac8c..d6b40fa7f7 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -523,7 +523,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals /// The remaining bytes in the segment block. private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) { - Span temp = stackalloc byte[markerContentByteSize]; + Span temp = new byte[markerContentByteSize]; char[] chars = new char[markerContentByteSize]; JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index cc6042b6ef..1b2b4cbb1c 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -185,7 +185,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals // Length (comment strings lengths) + (comments markers with payload sizes) int commentsBytes = metadata.Comments.Sum(x => x.Length) + (metadata.Comments.Count * 4); int commentStart = 0; - Span commentBuffer = stackalloc byte[commentsBytes]; + Span commentBuffer = new byte[commentsBytes]; foreach (Memory comment in metadata.Comments) { diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index fa54859a36..bd68eaf208 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -137,7 +137,7 @@ public partial class JpegEncoderTests [MemberData(nameof(QualityFiles))] public void Encode_PreservesQuality(string imagePath, int quality) { - var testFile = TestFile.Create(imagePath); + TestFile testFile = TestFile.Create(imagePath); using (Image input = testFile.CreateRgba32Image()) { using (var memStream = new MemoryStream()) @@ -160,7 +160,7 @@ public partial class JpegEncoderTests where TPixel : unmanaged, IPixel { // arrange - using var input = provider.GetImage(JpegDecoder.Instance); + using Image input = provider.GetImage(JpegDecoder.Instance); using var memStream = new MemoryStream(); // act @@ -168,7 +168,7 @@ public partial class JpegEncoderTests // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(1, actual.Comments.Count); @@ -190,7 +190,7 @@ public partial class JpegEncoderTests // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(2, actual.Comments?.Count); From 9260be9d2996c614d7c992540ebef6ab4d2ca7b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Thu, 25 Jan 2024 19:19:41 +0100 Subject: [PATCH 138/219] Add com character limit, comment as IList, remove unnecessary extension methods --- .../Formats/Jpeg/JpegEncoderCore.cs | 43 +++++++++++-------- src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 2 +- .../Formats/Jpeg/MetadataExtensions.cs | 33 -------------- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 4 +- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 12 +++--- 5 files changed, 34 insertions(+), 60 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 1b2b4cbb1c..4dc9202070 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -177,39 +177,46 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals /// The image metadata. private void WriteComment(JpegMetadata metadata) { - if (metadata.Comments is { Count: 0 }) + int maxCommentLength = 65533; + + if (metadata.Comments.Count == 0) { return; } - // Length (comment strings lengths) + (comments markers with payload sizes) - int commentsBytes = metadata.Comments.Sum(x => x.Length) + (metadata.Comments.Count * 4); - int commentStart = 0; - Span commentBuffer = new byte[commentsBytes]; - - foreach (Memory comment in metadata.Comments) + for (int i = 0; i < metadata.Comments.Count; i++) { - int totalComLength = comment.Length + 4; + Memory chars = metadata.Comments[i]; + + if (chars.Length > maxCommentLength) + { + Memory splitComment = chars.Slice(maxCommentLength, chars.Length - maxCommentLength); + metadata.Comments.Insert(i + 1, splitComment); - Span commentData = commentBuffer.Slice(commentStart, totalComLength); - Span markers = commentData.Slice(0, 2); - Span payloadSize = commentData.Slice(2, 2); - Span payload = commentData.Slice(4, comment.Length); + // We don't want to keep the extra bytes + chars = chars.Slice(0, maxCommentLength); + } + + int commentLength = chars.Length + 4; + + Span comment = new byte[commentLength]; + Span markers = comment.Slice(0, 2); + Span payloadSize = comment.Slice(2, 2); + Span payload = comment.Slice(4, chars.Length); // Beginning of comment ff fe markers[0] = JpegConstants.Markers.XFF; markers[1] = JpegConstants.Markers.COM; // Write payload size - BinaryPrimitives.WriteInt16BigEndian(payloadSize, (short)(commentData.Length - 2)); + int comWithoutMarker = commentLength - 2; + payloadSize[0] = (byte)((comWithoutMarker >> 8) & 0xFF); + payloadSize[1] = (byte)(comWithoutMarker & 0xFF); - Encoding.ASCII.GetBytes(comment.Span, payload); + Encoding.ASCII.GetBytes(chars.Span, payload); - // Indicate begin of next comment in buffer - commentStart += totalComLength; + this.outputStream.Write(comment, 0, comment.Length); } - - this.outputStream.Write(commentBuffer, 0, commentBuffer.Length); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index 61fe3b214e..bf758dfd09 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -106,7 +106,7 @@ public class JpegMetadata : IDeepCloneable /// /// Gets the comments. /// - public ICollection>? Comments { get; } + public IList> Comments { get; } /// public IDeepCloneable DeepClone() => new JpegMetadata(this); diff --git a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs index 0c66fcbdd7..7330e74b79 100644 --- a/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs +++ b/src/ImageSharp/Formats/Jpeg/MetadataExtensions.cs @@ -18,37 +18,4 @@ public static partial class MetadataExtensions /// The metadata this method extends. /// The . public static JpegMetadata GetJpegMetadata(this ImageMetadata metadata) => metadata.GetFormatMetadata(JpegFormat.Instance); - - /// - /// Sets the comment in - /// - /// The metadata this method extends. - /// The index of comment to be inserted to. - /// The comment string. - public static void SetComment(this JpegMetadata metadata, int index, string comment) - { - if (metadata.Comments == null) - { - return; - } - - ASCIIEncoding encoding = new(); - byte[] bytes = encoding.GetBytes(comment); - List>? comments = metadata.Comments as List>; - comments?.Insert(index, encoding.GetChars(bytes)); - } - - /// - /// Gets the comments from - /// - /// The metadata this method extends. - /// The index of comment. - /// The IEnumerable string of comments. - public static string? GetComment(this JpegMetadata metadata, int index) => metadata.Comments?.ElementAtOrDefault(index).ToString(); - - /// - /// Clears comments - /// - /// The . - public static void ClearComments(this JpegMetadata metadata) => metadata.Comments?.Clear(); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index fb37a956d0..369e71abfc 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -434,8 +434,8 @@ public partial class JpegDecoderTests using Image image = provider.GetImage(JpegDecoder.Instance); JpegMetadata metadata = image.Metadata.GetJpegMetadata(); - Assert.Equal(1, metadata.Comments?.Count); - Assert.Equal(expectedComment, metadata.GetComment(0)); + Assert.Equal(1, metadata.Comments.Count); + Assert.Equal(expectedComment.ToCharArray(), metadata.Comments.ElementAtOrDefault(0)); image.DebugSave(provider); image.CompareToOriginal(provider); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index bd68eaf208..8cc64acea3 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -172,7 +172,7 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(1, actual.Comments.Count); - Assert.Equal("TEST COMMENT", actual.Comments.ElementAt(0).ToString()); + Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0).ToString()); } [Fact] @@ -184,8 +184,8 @@ public partial class JpegEncoderTests using var memStream = new MemoryStream(); // act - meta.SetComment(0, "First comment"); - meta.SetComment(1, "Second Comment"); + meta.Comments.Add("First comment".ToCharArray()); + meta.Comments.Add("Second Comment".ToCharArray()); input.Save(memStream, JpegEncoder); // assert @@ -193,9 +193,9 @@ public partial class JpegEncoderTests using Image output = Image.Load(memStream); JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); - Assert.Equal(2, actual.Comments?.Count); - Assert.Equal(meta.Comments?.ElementAt(0).ToString(), actual.Comments?.ElementAt(0).ToString()); - Assert.Equal(meta.Comments?.ElementAt(1).ToString(), actual.Comments?.ElementAt(1).ToString()); + Assert.Equal(2, actual.Comments.Count); + Assert.Equal(meta.Comments.ElementAtOrDefault(0).ToString(), actual.Comments.ElementAtOrDefault(0).ToString()); + Assert.Equal(meta.Comments.ElementAtOrDefault(1).ToString(), actual.Comments.ElementAtOrDefault(1).ToString()); } [Theory] From 980347e96fae9642cbd89bccb5a732d61865558c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Feb 2024 15:51:22 +1000 Subject: [PATCH 139/219] ENhance NormalizedFloatToByteSaturate --- src/ImageSharp/Common/Helpers/Numerics.cs | 20 +++ .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 4 +- .../SimdUtils.FallbackIntrinsics128.cs | 4 +- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 150 +++++++++++------- src/ImageSharp/Common/Helpers/SimdUtils.cs | 49 +++--- .../Common/Helpers/Vector128Utilities.cs | 87 +++++++++- .../Common/Helpers/Vector256Utilities.cs | 39 ++++- .../Common/Helpers/Vector512Utilities.cs | 37 ++++- .../PixelOperations/Rgba32.PixelOperations.cs | 16 +- .../ImageSharp.Benchmarks/Bulk/FromVector4.cs | 92 ++++++----- .../Bulk/FromVector4_Rgb24.cs | 66 +++----- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 5 +- .../TestUtilities/BasicSerializer.cs | 22 +-- .../FeatureTesting/FeatureTestRunner.cs | 81 ++++++---- 14 files changed, 443 insertions(+), 229 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index ca28a7aab5..5f85734e83 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -1010,6 +1010,26 @@ internal static class Numerics where TVector : struct => (uint)span.Length / (uint)Vector256.Count; + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this Span span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this ReadOnlySpan span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + /// /// Gets the count of vectors that safely fit into the given span. /// diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index ac122fc7d4..7d07dcaaed 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -95,7 +95,7 @@ internal static partial class SimdUtils /// internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - VerifySpanInput(source, dest, Vector.Count); + DebugVerifySpanInput(source, dest, Vector.Count); nuint n = dest.VectorCount(); @@ -130,7 +130,7 @@ internal static partial class SimdUtils ReadOnlySpan source, Span dest) { - VerifySpanInput(source, dest, Vector.Count); + DebugVerifySpanInput(source, dest, Vector.Count); nuint n = dest.VectorCount(); diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index a551cebd05..90b313fb90 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -69,7 +69,7 @@ internal static partial class SimdUtils [MethodImpl(InliningOptions.ColdPath)] internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) { - VerifySpanInput(source, dest, 4); + DebugVerifySpanInput(source, dest, 4); uint count = (uint)dest.Length / 4; if (count == 0) @@ -103,7 +103,7 @@ internal static partial class SimdUtils ReadOnlySpan source, Span dest) { - VerifySpanInput(source, dest, 4); + DebugVerifySpanInput(source, dest, 4); uint count = (uint)source.Length / 4; if (count == 0) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index f27852a823..feb55ebe59 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -17,8 +17,13 @@ internal static partial class SimdUtils { public static class HwIntrinsics { +#pragma warning disable SA1117 // Parameters should be on same line or separate lines +#pragma warning disable SA1137 // Elements should have the same indentation [MethodImpl(MethodImplOptions.AggressiveInlining)] // too much IL for JIT to inline, so give a hint - public static Vector256 PermuteMaskDeinterleave8x32() => Vector256.Create(0, 0, 0, 0, 4, 0, 0, 0, 1, 0, 0, 0, 5, 0, 0, 0, 2, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsInt32(); + public static Vector256 PermuteMaskDeinterleave8x32() => Vector256.Create(0, 4, 1, 5, 2, 6, 3, 7); + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 PermuteMaskDeinterleave16x32() => Vector512.Create(0, 4, 8, 12, 1, 5, 9, 13, 2, 6, 10, 14, 3, 7, 11, 15); [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 PermuteMaskEvenOdd8x32() => Vector256.Create(0, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, 6, 0, 0, 0, 1, 0, 0, 0, 3, 0, 0, 0, 5, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); @@ -38,17 +43,18 @@ internal static partial class SimdUtils [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector128 ShuffleMaskSlice4Nx16() => Vector128.Create(0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 0x80, 0x80, 0x80, 0x80); -#pragma warning disable SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector256 ShuffleMaskShiftAlpha() => Vector256.Create((byte) - 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15, - 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); + private static Vector256 ShuffleMaskShiftAlpha() => Vector256.Create( + (byte)0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15, + 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 PermuteMaskShiftAlpha8x32() => Vector256.Create( - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, - 5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); -#pragma warning restore SA1003, SA1116, SA1117 // Parameters should be on same line or separate lines + public static Vector256 PermuteMaskShiftAlpha8x32() + => Vector256.Create( + 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, + 5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); +#pragma warning restore SA1137 // Elements should have the same indentation +#pragma warning restore SA1117 // Parameters should be on same line or separate lines /// /// Shuffle single-precision (32-bit) floating-point elements in @@ -795,7 +801,7 @@ internal static partial class SimdUtils { if (Avx2.IsSupported) { - VerifySpanInput(source, dest, Vector256.Count); + DebugVerifySpanInput(source, dest, Vector256.Count); nuint n = dest.Vector256Count(); @@ -828,7 +834,7 @@ internal static partial class SimdUtils else { // Sse - VerifySpanInput(source, dest, Vector128.Count); + DebugVerifySpanInput(source, dest, Vector128.Count); nuint n = dest.Vector128Count(); @@ -881,17 +887,24 @@ internal static partial class SimdUtils /// /// as many elements as possible, slicing them down (keeping the remainder). /// + /// The source buffer. + /// The destination buffer. [MethodImpl(InliningOptions.ShortMethod)] internal static void NormalizedFloatToByteSaturateReduce( ref ReadOnlySpan source, - ref Span dest) + ref Span destination) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if (Avx2.IsSupported || Sse2.IsSupported) + if (Avx512BW.IsSupported || Avx2.IsSupported || Sse2.IsSupported || AdvSimd.IsSupported) { int remainder; - if (Avx2.IsSupported) + + if (Avx512BW.IsSupported) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Avx2.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector256.Count); } @@ -906,10 +919,10 @@ internal static partial class SimdUtils { NormalizedFloatToByteSaturate( source[..adjustedCount], - dest[..adjustedCount]); + destination[..adjustedCount]); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } @@ -917,25 +930,59 @@ internal static partial class SimdUtils /// /// Implementation of , which is faster on new .NET runtime. /// + /// The source buffer. + /// The destination buffer. /// /// Implementation is based on MagicScaler code: /// https://github.com/saucecontrol/PhotoSauce/blob/b5811908041200488aa18fdfd17df5fc457415dc/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L541-L622 /// internal static void NormalizedFloatToByteSaturate( ReadOnlySpan source, - Span dest) + Span destination) { - if (Avx2.IsSupported) + if (Avx512BW.IsSupported) { - VerifySpanInput(source, dest, Vector256.Count); + DebugVerifySpanInput(source, destination, Vector512.Count); + + nuint n = destination.Vector512Count(); - nuint n = dest.Vector256Count(); + ref Vector512 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector256 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + Vector512 scale = Vector512.Create((float)byte.MaxValue); + Vector512 mask = PermuteMaskDeinterleave16x32(); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + for (nuint i = 0; i < n; i++) + { + ref Vector512 s = ref Unsafe.Add(ref sourceBase, i * 4); + + Vector512 f0 = scale * s; + Vector512 f1 = scale * Unsafe.Add(ref s, 1); + Vector512 f2 = scale * Unsafe.Add(ref s, 2); + Vector512 f3 = scale * Unsafe.Add(ref s, 3); + + Vector512 w0 = Vector512Utilities.ConvertToInt32RoundToEven(f0); + Vector512 w1 = Vector512Utilities.ConvertToInt32RoundToEven(f1); + Vector512 w2 = Vector512Utilities.ConvertToInt32RoundToEven(f2); + Vector512 w3 = Vector512Utilities.ConvertToInt32RoundToEven(f3); + + Vector512 u0 = Avx512BW.PackSignedSaturate(w0, w1); + Vector512 u1 = Avx512BW.PackSignedSaturate(w2, w3); + Vector512 b = Avx512BW.PackUnsignedSaturate(u0, u1); + b = Avx512F.PermuteVar16x32(b.AsInt32(), mask).AsByte(); + + Unsafe.Add(ref destinationBase, i) = b; + } + } + else + if (Avx2.IsSupported) + { + DebugVerifySpanInput(source, destination, Vector256.Count); + + nuint n = destination.Vector256Count(); + + ref Vector256 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); Vector256 scale = Vector256.Create((float)byte.MaxValue); Vector256 mask = PermuteMaskDeinterleave8x32(); @@ -944,36 +991,33 @@ internal static partial class SimdUtils { ref Vector256 s = ref Unsafe.Add(ref sourceBase, i * 4); - Vector256 f0 = Avx.Multiply(scale, s); - Vector256 f1 = Avx.Multiply(scale, Unsafe.Add(ref s, 1)); - Vector256 f2 = Avx.Multiply(scale, Unsafe.Add(ref s, 2)); - Vector256 f3 = Avx.Multiply(scale, Unsafe.Add(ref s, 3)); + Vector256 f0 = scale * s; + Vector256 f1 = scale * Unsafe.Add(ref s, 1); + Vector256 f2 = scale * Unsafe.Add(ref s, 2); + Vector256 f3 = scale * Unsafe.Add(ref s, 3); - Vector256 w0 = Avx.ConvertToVector256Int32(f0); - Vector256 w1 = Avx.ConvertToVector256Int32(f1); - Vector256 w2 = Avx.ConvertToVector256Int32(f2); - Vector256 w3 = Avx.ConvertToVector256Int32(f3); + Vector256 w0 = Vector256Utilities.ConvertToInt32RoundToEven(f0); + Vector256 w1 = Vector256Utilities.ConvertToInt32RoundToEven(f1); + Vector256 w2 = Vector256Utilities.ConvertToInt32RoundToEven(f2); + Vector256 w3 = Vector256Utilities.ConvertToInt32RoundToEven(f3); Vector256 u0 = Avx2.PackSignedSaturate(w0, w1); Vector256 u1 = Avx2.PackSignedSaturate(w2, w3); Vector256 b = Avx2.PackUnsignedSaturate(u0, u1); b = Avx2.PermuteVar8x32(b.AsInt32(), mask).AsByte(); - Unsafe.Add(ref destBase, i) = b; + Unsafe.Add(ref destinationBase, i) = b; } } else { - // Sse - VerifySpanInput(source, dest, Vector128.Count); - - nuint n = dest.Vector128Count(); + // Sse, AdvSimd + DebugVerifySpanInput(source, destination, Vector128.Count); - ref Vector128 sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + nuint n = destination.Vector128Count(); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + ref Vector128 sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); Vector128 scale = Vector128.Create((float)byte.MaxValue); @@ -981,20 +1025,20 @@ internal static partial class SimdUtils { ref Vector128 s = ref Unsafe.Add(ref sourceBase, i * 4); - Vector128 f0 = Sse.Multiply(scale, s); - Vector128 f1 = Sse.Multiply(scale, Unsafe.Add(ref s, 1)); - Vector128 f2 = Sse.Multiply(scale, Unsafe.Add(ref s, 2)); - Vector128 f3 = Sse.Multiply(scale, Unsafe.Add(ref s, 3)); + Vector128 f0 = scale * s; + Vector128 f1 = scale * Unsafe.Add(ref s, 1); + Vector128 f2 = scale * Unsafe.Add(ref s, 2); + Vector128 f3 = scale * Unsafe.Add(ref s, 3); - Vector128 w0 = Sse2.ConvertToVector128Int32(f0); - Vector128 w1 = Sse2.ConvertToVector128Int32(f1); - Vector128 w2 = Sse2.ConvertToVector128Int32(f2); - Vector128 w3 = Sse2.ConvertToVector128Int32(f3); + Vector128 w0 = Vector128Utilities.ConvertToInt32RoundToEven(f0); + Vector128 w1 = Vector128Utilities.ConvertToInt32RoundToEven(f1); + Vector128 w2 = Vector128Utilities.ConvertToInt32RoundToEven(f2); + Vector128 w3 = Vector128Utilities.ConvertToInt32RoundToEven(f3); - Vector128 u0 = Sse2.PackSignedSaturate(w0, w1); - Vector128 u1 = Sse2.PackSignedSaturate(w2, w3); + Vector128 u0 = Vector128Utilities.PackSignedSaturate(w0, w1); + Vector128 u1 = Vector128Utilities.PackSignedSaturate(w2, w3); - Unsafe.Add(ref destBase, i) = Sse2.PackUnsignedSaturate(u0, u1); + Unsafe.Add(ref destinationBase, i) = Vector128Utilities.PackUnsignedSaturate(u0, u1); } } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 497e3cc6a0..002c1f8da0 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -94,35 +94,31 @@ internal static partial class SimdUtils } /// - /// Convert all values normalized into [0..1] from 'source' into 'dest' buffer of . + /// Convert all values normalized into [0..1] from 'source' into 'destination' buffer of . /// The values are scaled up into [0-255] and rounded, overflows are clamped. - /// should be the of the same size as , + /// should be the of the same size as , /// but there are no restrictions on the span's length. /// /// The source span of floats - /// The destination span of bytes + /// The destination span of bytes [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span dest) + internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span destination) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref dest); - - // Also deals with the remainder from previous conversions: - FallbackIntrinsics128.NormalizedFloatToByteSaturateReduce(ref source, ref dest); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); + HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref destination); // Deal with the remainder: if (source.Length > 0) { - ConvertNormalizedFloatToByteRemainder(source, dest); + ConvertNormalizedFloatToByteRemainder(source, destination); } } [MethodImpl(InliningOptions.ColdPath)] - private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span dest) + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span destination) { ref byte sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(dest); + ref float dBase = ref MemoryMarshal.GetReference(destination); // There are at most 3 elements at this point, having a for loop is overkill. // Let's minimize the no. of instructions! @@ -140,23 +136,14 @@ internal static partial class SimdUtils } } - [MethodImpl(InliningOptions.ColdPath)] - private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span dest) + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span destination) { ref float sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(dest); - - switch (source.Length) + ref byte dBase = ref MemoryMarshal.GetReference(destination); + for (int i = 0; i < source.Length; i++) { - case 3: - Unsafe.Add(ref dBase, 2) = ConvertToByte(Unsafe.Add(ref sBase, 2)); - goto case 2; - case 2: - Unsafe.Add(ref dBase, 1) = ConvertToByte(Unsafe.Add(ref sBase, 1)); - goto case 1; - case 1: - dBase = ConvertToByte(sBase); - break; + Unsafe.Add(ref dBase, i) = ConvertToByte(Unsafe.Add(ref sBase, i)); } } @@ -173,7 +160,7 @@ internal static partial class SimdUtils } [Conditional("DEBUG")] - private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + private static void DebugVerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) { DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( @@ -183,11 +170,11 @@ internal static partial class SimdUtils } [Conditional("DEBUG")] - private static void VerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) + private static void DebugVerifySpanInput(ReadOnlySpan source, Span destination, int shouldBeDivisibleBy) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); DebugGuard.IsTrue( - Numerics.ModuloP2(dest.Length, shouldBeDivisibleBy) == 0, + Numerics.ModuloP2(destination.Length, shouldBeDivisibleBy) == 0, nameof(source), $"length should be divisible by {shouldBeDivisibleBy}!"); } diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index 981f9a47f7..a07fa8ca6e 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -26,7 +26,7 @@ internal static class Vector128Utilities public static bool SupportsShuffleFloat { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Sse.IsSupported; + get => Sse.IsSupported || AdvSimd.IsSupported; } /// @@ -62,6 +62,7 @@ internal static class Vector128Utilities /// The input vector from which values are selected. /// The shuffle control byte. /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Shuffle(Vector128 vector, [ConstantExpected] byte control) { if (Sse.IsSupported) @@ -69,6 +70,17 @@ internal static class Vector128Utilities return Sse.Shuffle(vector, vector, control); } + if (AdvSimd.IsSupported) + { +#pragma warning disable CA1857 // A constant is expected for the parameter + Vector128 result = Vector128.Create(AdvSimd.Extract(vector, (byte)(control & 0x3))); + result = AdvSimd.Insert(result, 1, AdvSimd.Extract(vector, (byte)((control >> 2) & 0x3))); + result = AdvSimd.Insert(result, 2, AdvSimd.Extract(vector, (byte)((control >> 4) & 0x3))); + result = AdvSimd.Insert(result, 3, AdvSimd.Extract(vector, (byte)((control >> 6) & 0x3))); +#pragma warning restore CA1857 // A constant is expected for the parameter + return result; + } + ThrowUnreachableException(); return default; } @@ -84,6 +96,7 @@ internal static class Vector128Utilities /// /// A new vector containing the values from selected by the given . /// + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 Shuffle(Vector128 vector, Vector128 indices) { if (Ssse3.IsSupported) @@ -155,6 +168,7 @@ internal static class Vector128Utilities /// The right hand source vector. /// An 8-bit mask used for the operation. /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector128 AlignRight(Vector128 left, Vector128 right, [ConstantExpected(Max = (byte)15)] byte mask) { if (Ssse3.IsSupported) @@ -171,6 +185,77 @@ internal static class Vector128Utilities return default; } + /// + /// Performs a conversion from a 128-bit vector of 4 single-precision floating-point values to a 128-bit vector of 4 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 ConvertToInt32RoundToEven(Vector128 vector) + { + if (Sse2.IsSupported) + { + return Sse2.ConvertToVector128Int32(vector); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ConvertToInt32RoundToEven(vector); + } + + Vector128 sign = vector & Vector128.Create(-0.0f); + Vector128 val_2p23_f32 = sign | Vector128.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector128.ConvertToInt32(val_2p23_f32 | sign); + } + + /// + /// Packs signed 16-bit integers to unsigned 8-bit integers and saturates. + /// + /// The left hand source vector. + /// The right hand source vector. + /// The . + public static Vector128 PackUnsignedSaturate(Vector128 left, Vector128 right) + { + if (Sse2.IsSupported) + { + return Sse2.PackUnsignedSaturate(left, right); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUnsignedUpper(AdvSimd.ExtractNarrowingSaturateUnsignedLower(left), right); + } + + ThrowUnreachableException(); + return default; + } + + /// + /// Packs signed 32-bit integers to signed 16-bit integers and saturates. + /// + /// The left hand source vector. + /// The right hand source vector. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector128 PackSignedSaturate(Vector128 left, Vector128 right) + { + if (Sse2.IsSupported) + { + return Sse2.PackSignedSaturate(left, right); + } + + if (AdvSimd.IsSupported) + { + return AdvSimd.ExtractNarrowingSaturateUpper(AdvSimd.ExtractNarrowingSaturateLower(left), right); + } + + ThrowUnreachableException(); + return default; + } + [DoesNotReturn] private static void ThrowUnreachableException() => throw new UnreachableException(); } diff --git a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs index 14fa24b315..6e8c0d1de4 100644 --- a/src/ImageSharp/Common/Helpers/Vector256Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector256Utilities.cs @@ -25,7 +25,7 @@ internal static class Vector256Utilities public static bool SupportsShuffleFloat { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Avx.IsSupported; + get => Avx.IsSupported || Sse.IsSupported; } /// @@ -43,6 +43,7 @@ internal static class Vector256Utilities /// The input vector from which values are selected. /// The shuffle control byte. /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Shuffle(Vector256 vector, [ConstantExpected] byte control) { if (Avx.IsSupported) @@ -50,6 +51,13 @@ internal static class Vector256Utilities return Avx.Shuffle(vector, vector, control); } + if (Sse.IsSupported) + { + Vector128 lower = vector.GetLower(); + Vector128 upper = vector.GetUpper(); + return Vector256.Create(Sse.Shuffle(lower, lower, control), Sse.Shuffle(upper, upper, control)); + } + ThrowUnreachableException(); return default; } @@ -62,6 +70,7 @@ internal static class Vector256Utilities /// The per-element indices used to select a value from . /// /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Vector256 Shuffle(Vector256 vector, Vector256 indices) { if (Avx2.IsSupported) @@ -73,6 +82,34 @@ internal static class Vector256Utilities return default; } + /// + /// Performs a conversion from a 256-bit vector of 8 single-precision floating-point values to a 256-bit vector of 8 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector256 ConvertToInt32RoundToEven(Vector256 vector) + { + if (Avx.IsSupported) + { + return Avx.ConvertToVector256Int32(vector); + } + + if (Sse2.IsSupported) + { + Vector128 lower = Sse2.ConvertToVector128Int32(vector.GetLower()); + Vector128 upper = Sse2.ConvertToVector128Int32(vector.GetUpper()); + return Vector256.Create(lower, upper); + } + + Vector256 sign = vector & Vector256.Create(-0.0f); + Vector256 val_2p23_f32 = sign | Vector256.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector256.ConvertToInt32(val_2p23_f32 | sign); + } + [DoesNotReturn] private static void ThrowUnreachableException() => throw new UnreachableException(); } diff --git a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs index 5488b40644..0165af90ef 100644 --- a/src/ImageSharp/Common/Helpers/Vector512Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector512Utilities.cs @@ -25,7 +25,7 @@ internal static class Vector512Utilities public static bool SupportsShuffleFloat { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Avx512F.IsSupported; + get => Avx512F.IsSupported || Avx.IsSupported; } /// @@ -51,6 +51,13 @@ internal static class Vector512Utilities return Avx512F.Shuffle(vector, vector, control); } + if (Avx.IsSupported) + { + Vector256 lower = vector.GetLower(); + Vector256 upper = vector.GetUpper(); + return Vector512.Create(Avx.Shuffle(lower, lower, control), Avx.Shuffle(upper, upper, control)); + } + ThrowUnreachableException(); return default; } @@ -75,6 +82,34 @@ internal static class Vector512Utilities return default; } + /// + /// Performs a conversion from a 512-bit vector of 16 single-precision floating-point values to a 512-bit vector of 16 signed 32-bit integer values. + /// Rounding is equivalent to . + /// + /// The value to convert. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Vector512 ConvertToInt32RoundToEven(Vector512 vector) + { + if (Avx512F.IsSupported) + { + return Avx512F.ConvertToVector512Int32(vector); + } + + if (Avx.IsSupported) + { + Vector256 lower = Avx.ConvertToVector256Int32(vector.GetLower()); + Vector256 upper = Avx.ConvertToVector256Int32(vector.GetUpper()); + return Vector512.Create(lower, upper); + } + + Vector512 sign = vector & Vector512.Create(-0.0f); + Vector512 val_2p23_f32 = sign | Vector512.Create(8388608.0f); + + val_2p23_f32 = (vector + val_2p23_f32) - val_2p23_f32; + return Vector512.ConvertToInt32(val_2p23_f32 | sign); + } + [DoesNotReturn] private static void ThrowUnreachableException() => throw new UnreachableException(); } diff --git a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs index ed89585dcf..065e34c336 100644 --- a/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs +++ b/src/ImageSharp/PixelFormats/PixelImplementations/PixelOperations/Rgba32.PixelOperations.cs @@ -20,15 +20,15 @@ public partial struct Rgba32 /// public override void ToVector4( Configuration configuration, - ReadOnlySpan sourcePixels, + ReadOnlySpan source, Span destinationVectors, PixelConversionModifiers modifiers) { - Guard.DestinationShouldNotBeTooShort(sourcePixels, destinationVectors, nameof(destinationVectors)); + Guard.DestinationShouldNotBeTooShort(source, destinationVectors, nameof(destinationVectors)); - destinationVectors = destinationVectors[..sourcePixels.Length]; + destinationVectors = destinationVectors[..source.Length]; SimdUtils.ByteToNormalizedFloat( - MemoryMarshal.Cast(sourcePixels), + MemoryMarshal.Cast(source), MemoryMarshal.Cast(destinationVectors)); Vector4Converters.ApplyForwardConversionModifiers(destinationVectors, modifiers); } @@ -37,16 +37,16 @@ public partial struct Rgba32 public override void FromVector4Destructive( Configuration configuration, Span sourceVectors, - Span destinationPixels, + Span destination, PixelConversionModifiers modifiers) { - Guard.DestinationShouldNotBeTooShort(sourceVectors, destinationPixels, nameof(destinationPixels)); + Guard.DestinationShouldNotBeTooShort(sourceVectors, destination, nameof(destination)); - destinationPixels = destinationPixels[..sourceVectors.Length]; + destination = destination[..sourceVectors.Length]; Vector4Converters.ApplyBackwardConversionModifiers(sourceVectors, modifiers); SimdUtils.NormalizedFloatToByteSaturate( MemoryMarshal.Cast(sourceVectors), - MemoryMarshal.Cast(destinationPixels)); + MemoryMarshal.Cast(destination)); } /// diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs index ecd16b9578..dff687fa12 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs @@ -18,9 +18,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; public abstract class FromVector4 where TPixel : unmanaged, IPixel { - protected IMemoryOwner source; + protected IMemoryOwner Source { get; set; } - protected IMemoryOwner destination; + protected IMemoryOwner Destination { get; set; } protected Configuration Configuration => Configuration.Default; @@ -31,22 +31,22 @@ public abstract class FromVector4 [GlobalSetup] public void Setup() { - this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); - this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Source = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] public void Cleanup() { - this.destination.Dispose(); - this.source.Dispose(); + this.Destination.Dispose(); + this.Source.Dispose(); } // [Benchmark] public void PerElement() { - ref Vector4 s = ref MemoryMarshal.GetReference(this.source.GetSpan()); - ref TPixel d = ref MemoryMarshal.GetReference(this.destination.GetSpan()); + ref Vector4 s = ref MemoryMarshal.GetReference(this.Source.GetSpan()); + ref TPixel d = ref MemoryMarshal.GetReference(this.Destination.GetSpan()); for (nuint i = 0; i < (uint)this.Count; i++) { Unsafe.Add(ref d, i) = TPixel.FromVector4(Unsafe.Add(ref s, i)); @@ -55,11 +55,11 @@ public abstract class FromVector4 [Benchmark(Baseline = true)] public void PixelOperations_Base() - => new PixelOperations().FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); + => new PixelOperations().FromVector4Destructive(this.Configuration, this.Source.GetSpan(), this.Destination.GetSpan()); [Benchmark] public void PixelOperations_Specialized() - => PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.source.GetSpan(), this.destination.GetSpan()); + => PixelOperations.Instance.FromVector4Destructive(this.Configuration, this.Source.GetSpan(), this.Destination.GetSpan()); } public class FromVector4Rgba32 : FromVector4 @@ -67,8 +67,8 @@ public class FromVector4Rgba32 : FromVector4 [Benchmark] public void FallbackIntrinsics128() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(sBytes, dFloats); } @@ -76,8 +76,8 @@ public class FromVector4Rgba32 : FromVector4 [Benchmark] public void ExtendedIntrinsic() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); } @@ -85,8 +85,8 @@ public class FromVector4Rgba32 : FromVector4 [Benchmark] public void UseHwIntrinsics() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.HwIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); } @@ -96,8 +96,8 @@ public class FromVector4Rgba32 : FromVector4 [Benchmark] public void UseAvx2_Grouped() { - Span src = MemoryMarshal.Cast(this.source.GetSpan()); - Span dest = MemoryMarshal.Cast(this.destination.GetSpan()); + Span src = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dest = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dest.Length / (uint)Vector.Count; @@ -107,7 +107,7 @@ public class FromVector4Rgba32 : FromVector4 ref byte maskBase = ref MemoryMarshal.GetReference(PermuteMaskDeinterleave8x32); Vector256 mask = Unsafe.As>(ref maskBase); - var maxBytes = Vector256.Create(255f); + Vector256 maxBytes = Vector256.Create(255f); for (nuint i = 0; i < n; i++) { @@ -137,25 +137,37 @@ public class FromVector4Rgba32 : FromVector4 } } - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector256 ConvertToInt32(Vector256 vf, Vector256 scale) - { - vf = Avx.Multiply(scale, vf); - return Avx.ConvertToVector256Int32(vf); - } - - // *** RESULTS 2020 March: *** - // Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores - // .NET Core SDK=3.1.200-preview-014971 - // Job-IUZXZT : .NET Core 3.1.2 (CoreCLR 4.700.20.6602, CoreFX 4.700.20.6702), X64 RyuJIT - // - // | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | - // |---------------------------- |------ |-----------:|------------:|----------:|------:|--------:|------:|------:|------:|----------:| - // | FallbackIntrinsics128 | 1024 | 2,952.6 ns | 1,680.77 ns | 92.13 ns | 3.32 | 0.16 | - | - | - | - | - // | BasicIntrinsics256 | 1024 | 1,664.5 ns | 928.11 ns | 50.87 ns | 1.87 | 0.09 | - | - | - | - | - // | ExtendedIntrinsic | 1024 | 890.6 ns | 375.48 ns | 20.58 ns | 1.00 | 0.00 | - | - | - | - | - // | UseAvx2 | 1024 | 299.0 ns | 30.47 ns | 1.67 ns | 0.34 | 0.01 | - | - | - | - | - // | UseAvx2_Grouped | 1024 | 318.1 ns | 48.19 ns | 2.64 ns | 0.36 | 0.01 | - | - | - | - | - // | PixelOperations_Base | 1024 | 8,136.9 ns | 1,834.82 ns | 100.57 ns | 9.14 | 0.26 | - | - | - | 24 B | - // | PixelOperations_Specialized | 1024 | 951.1 ns | 123.93 ns | 6.79 ns | 1.07 | 0.03 | - | - | - | - | + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + Job-YJYLLR : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + Runtime=.NET 8.0 Arguments=/p:DebugType=portable IterationCount=3 + LaunchCount=1 WarmupCount=3 + + | Method | Count | Mean | Error | StdDev | Ratio | RatioSD | Allocated | Alloc Ratio | + |---------------------------- |------ |------------:|-------------:|-----------:|------:|--------:|----------:|------------:| + | PixelOperations_Base | 64 | 114.80 ns | 16.459 ns | 0.902 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 64 | 28.91 ns | 80.482 ns | 4.411 ns | 0.25 | 0.04 | - | NA | + | FallbackIntrinsics128 | 64 | 133.60 ns | 23.750 ns | 1.302 ns | 1.16 | 0.02 | - | NA | + | ExtendedIntrinsic | 64 | 40.11 ns | 10.183 ns | 0.558 ns | 0.35 | 0.01 | - | NA | + | UseHwIntrinsics | 64 | 14.71 ns | 4.860 ns | 0.266 ns | 0.13 | 0.00 | - | NA | + | UseAvx2_Grouped | 64 | 20.23 ns | 11.619 ns | 0.637 ns | 0.18 | 0.00 | - | NA | + | | | | | | | | | | + | PixelOperations_Base | 256 | 387.94 ns | 31.591 ns | 1.732 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 256 | 50.93 ns | 22.388 ns | 1.227 ns | 0.13 | 0.00 | - | NA | + | FallbackIntrinsics128 | 256 | 509.72 ns | 249.926 ns | 13.699 ns | 1.31 | 0.04 | - | NA | + | ExtendedIntrinsic | 256 | 140.32 ns | 9.353 ns | 0.513 ns | 0.36 | 0.00 | - | NA | + | UseHwIntrinsics | 256 | 41.99 ns | 16.000 ns | 0.877 ns | 0.11 | 0.00 | - | NA | + | UseAvx2_Grouped | 256 | 63.81 ns | 2.360 ns | 0.129 ns | 0.16 | 0.00 | - | NA | + | | | | | | | | | | + | PixelOperations_Base | 2048 | 2,979.49 ns | 2,023.706 ns | 110.926 ns | 1.00 | 0.00 | - | NA | + | PixelOperations_Specialized | 2048 | 326.19 ns | 19.077 ns | 1.046 ns | 0.11 | 0.00 | - | NA | + | FallbackIntrinsics128 | 2048 | 3,885.95 ns | 411.078 ns | 22.533 ns | 1.31 | 0.05 | - | NA | + | ExtendedIntrinsic | 2048 | 1,078.58 ns | 136.960 ns | 7.507 ns | 0.36 | 0.01 | - | NA | + | UseHwIntrinsics | 2048 | 312.07 ns | 68.662 ns | 3.764 ns | 0.10 | 0.00 | - | NA | + | UseAvx2_Grouped | 2048 | 451.83 ns | 41.742 ns | 2.288 ns | 0.15 | 0.01 | - | NA | + */ } diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs index 27fab64dd2..c6125ef8f0 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4_Rgb24.cs @@ -7,48 +7,26 @@ using SixLabors.ImageSharp.PixelFormats; namespace SixLabors.ImageSharp.Benchmarks.Bulk; [Config(typeof(Config.Short))] -public class FromVector4_Rgb24 : FromVector4 -{ -} +public class FromVector4_Rgb24 : FromVector4; -// 2020-11-02 -// ########## -// -// BenchmarkDotNet = v0.12.1, OS = Windows 10.0.19041.572(2004 /?/ 20H1) -// Intel Core i7-8650U CPU 1.90GHz (Kaby Lake R), 1 CPU, 8 logical and 4 physical cores -// .NET Core SDK=3.1.403 -// [Host] : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT -// Job-XYEQXL : .NET Framework 4.8 (4.8.4250.0), X64 RyuJIT -// Job-HSXNJV : .NET Core 2.1.23 (CoreCLR 4.6.29321.03, CoreFX 4.6.29321.01), X64 RyuJIT -// Job-YUREJO : .NET Core 3.1.9 (CoreCLR 4.700.20.47201, CoreFX 4.700.20.47203), X64 RyuJIT -// -// IterationCount=3 LaunchCount=1 WarmupCount=3 -// -// | Method | Job | Runtime | Count | Mean | Error | StdDev | Ratio | RatioSD | Gen 0 | Gen 1 | Gen 2 | Allocated | -// |---------------------------- |----------- |-------------- |------ |-----------:|------------:|----------:|------:|--------:|-------:|------:|------:|----------:| -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 64 | 343.2 ns | 305.91 ns | 16.77 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 64 | 320.8 ns | 19.93 ns | 1.09 ns | 0.94 | 0.05 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 64 | 234.3 ns | 17.98 ns | 0.99 ns | 1.00 | 0.00 | 0.0052 | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 64 | 246.0 ns | 82.34 ns | 4.51 ns | 1.05 | 0.02 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 64 | 222.3 ns | 39.46 ns | 2.16 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 64 | 243.4 ns | 33.58 ns | 1.84 ns | 1.09 | 0.01 | - | - | - | - | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 256 | 824.9 ns | 32.77 ns | 1.80 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 256 | 967.0 ns | 39.09 ns | 2.14 ns | 1.17 | 0.01 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 256 | 756.9 ns | 94.43 ns | 5.18 ns | 1.00 | 0.00 | 0.0048 | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 256 | 1,003.3 ns | 3,192.09 ns | 174.97 ns | 1.32 | 0.22 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 256 | 748.6 ns | 248.03 ns | 13.60 ns | 1.00 | 0.00 | 0.0057 | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 256 | 437.0 ns | 36.48 ns | 2.00 ns | 0.58 | 0.01 | 0.0172 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-XYEQXL | .NET 4.7.2 | 2048 | 5,751.6 ns | 704.24 ns | 38.60 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-XYEQXL | .NET 4.7.2 | 2048 | 4,391.6 ns | 718.17 ns | 39.37 ns | 0.76 | 0.00 | 0.0153 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-HSXNJV | .NET Core 2.1 | 2048 | 6,202.0 ns | 1,815.18 ns | 99.50 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-HSXNJV | .NET Core 2.1 | 2048 | 4,225.6 ns | 1,004.03 ns | 55.03 ns | 0.68 | 0.01 | 0.0153 | - | - | 72 B | -// | | | | | | | | | | | | | | -// | PixelOperations_Base | Job-YUREJO | .NET Core 3.1 | 2048 | 6,157.1 ns | 2,516.98 ns | 137.96 ns | 1.00 | 0.00 | - | - | - | 24 B | -// | PixelOperations_Specialized | Job-YUREJO | .NET Core 3.1 | 2048 | 1,822.7 ns | 1,764.43 ns | 96.71 ns | 0.30 | 0.02 | 0.0172 | - | - | 72 B | +/* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3) +11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores +.NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + Job-NEHCEM : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + +Runtime=.NET 8.0 Arguments=/p:DebugType=portable IterationCount=3 +LaunchCount=1 WarmupCount=3 + +| Method | Count | Mean | Error | StdDev | Ratio | Gen0 | Allocated | Alloc Ratio | +|---------------------------- |------ |------------:|----------:|---------:|------:|-------:|----------:|------------:| +| PixelOperations_Base | 64 | 95.87 ns | 13.60 ns | 0.745 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 64 | 97.34 ns | 30.34 ns | 1.663 ns | 1.02 | - | - | NA | +| | | | | | | | | | +| PixelOperations_Base | 256 | 337.80 ns | 88.10 ns | 4.829 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 256 | 195.07 ns | 30.54 ns | 1.674 ns | 0.58 | 0.0153 | 96 B | NA | +| | | | | | | | | | +| PixelOperations_Base | 2048 | 2,561.79 ns | 162.45 ns | 8.905 ns | 1.00 | - | - | NA | +| PixelOperations_Specialized | 2048 | 741.85 ns | 18.05 ns | 0.989 ns | 0.29 | 0.0153 | 96 B | NA | + */ diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index c81eaea633..2003716796 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -112,6 +112,7 @@ public partial class SimdUtilsTests public static readonly TheoryData ArraySizesDivisibleBy4 = new() { 0, 4, 8, 28, 1020 }; public static readonly TheoryData ArraySizesDivisibleBy3 = new() { 0, 3, 9, 36, 957 }; public static readonly TheoryData ArraySizesDivisibleBy32 = new() { 0, 32, 512 }; + public static readonly TheoryData ArraySizesDivisibleBy64 = new() { 0, 64, 512 }; public static readonly TheoryData ArbitraryArraySizes = new() { 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520 }; @@ -199,7 +200,7 @@ public partial class SimdUtilsTests } [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] + [MemberData(nameof(ArraySizesDivisibleBy64))] public void HwIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) { if (!Sse2.IsSupported) @@ -214,7 +215,7 @@ public partial class SimdUtilsTests FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, count, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512BW | HwIntrinsics.DisableAVX2); } [Theory] diff --git a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs index d161b80197..216ed95b8b 100644 --- a/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs +++ b/tests/ImageSharp.Tests/TestUtilities/BasicSerializer.cs @@ -13,14 +13,14 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities; /// internal class BasicSerializer : IXunitSerializationInfo { - private readonly Dictionary map = new Dictionary(); + private readonly Dictionary map = []; public const char Separator = ':'; private string DumpToString(Type type) { - using var ms = new MemoryStream(); - using var writer = new StreamWriter(ms); + using MemoryStream ms = new(); + using StreamWriter writer = new(ms); writer.WriteLine(type.FullName); foreach (KeyValuePair kv in this.map) { @@ -29,16 +29,16 @@ internal class BasicSerializer : IXunitSerializationInfo writer.Flush(); byte[] data = ms.ToArray(); - return System.Convert.ToBase64String(data); + return Convert.ToBase64String(data); } private Type LoadDump(string dump) { - byte[] data = System.Convert.FromBase64String(dump); + byte[] data = Convert.FromBase64String(dump); - using var ms = new MemoryStream(data); - using var reader = new StreamReader(ms); - var type = Type.GetType(reader.ReadLine()); + using MemoryStream ms = new(data); + using StreamReader reader = new(ms); + Type type = Type.GetType(reader.ReadLine()); for (string s = reader.ReadLine(); s != null; s = reader.ReadLine()) { string[] kv = s.Split(Separator); @@ -50,7 +50,7 @@ internal class BasicSerializer : IXunitSerializationInfo public static string Serialize(IXunitSerializable serializable) { - var serializer = new BasicSerializer(); + BasicSerializer serializer = new(); serializable.Serialize(serializer); return serializer.DumpToString(serializable.GetType()); } @@ -58,10 +58,10 @@ internal class BasicSerializer : IXunitSerializationInfo public static T Deserialize(string dump) where T : IXunitSerializable { - var serializer = new BasicSerializer(); + BasicSerializer serializer = new(); Type type = serializer.LoadDump(dump); - var result = (T)Activator.CreateInstance(type); + T result = (T)Activator.CreateInstance(type); result.Deserialize(serializer); return result; } diff --git a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs index 5a9a72f967..07ad5e8f03 100644 --- a/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs +++ b/tests/ImageSharp.Tests/TestUtilities/FeatureTesting/FeatureTestRunner.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Diagnostics; +using System.Globalization; using Microsoft.DotNet.RemoteExecutor; using Xunit.Abstractions; @@ -12,7 +13,7 @@ namespace SixLabors.ImageSharp.Tests.TestUtilities; /// public static class FeatureTestRunner { - private static readonly char[] SplitChars = { ',', ' ' }; + private static readonly char[] SplitChars = [',', ' ']; /// /// Allows the deserialization of parameters passed to the feature test. @@ -40,7 +41,7 @@ public static class FeatureTestRunner /// The value. public static T Deserialize(string value) where T : IConvertible - => (T)Convert.ChangeType(value, typeof(T)); + => (T)Convert.ChangeType(value, typeof(T), CultureInfo.InvariantCulture); /// /// Runs the given test within an environment @@ -127,6 +128,7 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -170,6 +172,7 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -214,6 +217,8 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. + /// The addition type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -261,6 +266,7 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The intrinsics features. /// The value to pass as a parameter to the test action. @@ -307,6 +313,7 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The value to pass as a parameter to the test action. /// The intrinsics features. @@ -350,6 +357,7 @@ public static class FeatureTestRunner /// Runs the given test within an environment /// where the given features. /// + /// The type of argument. /// The test action to run. /// The value to pass as a parameter #0 to the test action. /// The value to pass as a parameter #1 to the test action. @@ -395,10 +403,10 @@ public static class FeatureTestRunner internal static Dictionary ToFeatureKeyValueCollection(this HwIntrinsics intrinsics) { // Loop through and translate the given values into COMPlus equivalents - Dictionary features = new(); + Dictionary features = []; foreach (string intrinsic in intrinsics.ToString("G").Split(SplitChars, StringSplitOptions.RemoveEmptyEntries)) { - HwIntrinsics key = (HwIntrinsics)Enum.Parse(typeof(HwIntrinsics), intrinsic); + HwIntrinsics key = Enum.Parse(intrinsic); switch (intrinsic) { case nameof(HwIntrinsics.AllowAll): @@ -418,40 +426,47 @@ public static class FeatureTestRunner } /// -/// See -/// -/// ends up impacting all SIMD support(including System.Numerics) -/// but not things like , , and . -/// +/// See /// [Flags] #pragma warning disable RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). -public enum HwIntrinsics +public enum HwIntrinsics : long #pragma warning restore RCS1135 // Declare enum member with zero value (when enum has FlagsAttribute). { // Use flags so we can pass multiple values without using params. // Don't base on 0 or use inverse for All as that doesn't translate to string values. - DisableHWIntrinsic = 1 << 0, - DisableSSE = 1 << 1, - DisableSSE2 = 1 << 2, - DisableAES = 1 << 3, - DisablePCLMULQDQ = 1 << 4, - DisableSSE3 = 1 << 5, - DisableSSSE3 = 1 << 6, - DisableSSE41 = 1 << 7, - DisableSSE42 = 1 << 8, - DisablePOPCNT = 1 << 9, - DisableAVX = 1 << 10, - DisableFMA = 1 << 11, - DisableAVX2 = 1 << 12, - DisableBMI1 = 1 << 13, - DisableBMI2 = 1 << 14, - DisableLZCNT = 1 << 15, - DisableArm64AdvSimd = 1 << 16, - DisableArm64Crc32 = 1 << 17, - DisableArm64Dp = 1 << 18, - DisableArm64Aes = 1 << 19, - DisableArm64Sha1 = 1 << 20, - DisableArm64Sha256 = 1 << 21, - AllowAll = 1 << 22 + DisableHWIntrinsic = 1L << 0, + DisableSSE = 1L << 1, + DisableSSE2 = 1L << 2, + DisableAES = 1L << 3, + DisablePCLMULQDQ = 1L << 4, + DisableSSE3 = 1L << 5, + DisableSSSE3 = 1L << 6, + DisableSSE41 = 1L << 7, + DisableSSE42 = 1L << 8, + DisablePOPCNT = 1L << 9, + DisableAVX = 1L << 10, + DisableFMA = 1L << 11, + DisableAVX2 = 1L << 12, + DisableAVXVNNI = 1L << 13, + DisableAVX512BW = 1L << 14, + DisableAVX512BW_VL = 1L << 15, + DisableAVX512CD = 1L << 16, + DisableAVX512CD_VL = 1L << 17, + DisableAVX512DQ = 1L << 18, + DisableAVX512DQ_VL = 1L << 19, + DisableAVX512F = 1L << 20, + DisableAVX512F_VL = 1L << 21, + DisableAVX512VBMI = 1L << 22, + DisableAVX512VBMI_VL = 1L << 23, + DisableBMI1 = 1L << 24, + DisableBMI2 = 1L << 25, + DisableLZCNT = 1L << 26, + DisableArm64AdvSimd = 1L << 27, + DisableArm64Crc32 = 1L << 28, + DisableArm64Dp = 1L << 29, + DisableArm64Aes = 1L << 30, + DisableArm64Sha1 = 1L << 31, + DisableArm64Sha256 = 1L << 32, + AllowAll = 1L << 33 } From 89cd8492f1aef9b233f3b6b203efa4083cc04215 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Feb 2024 18:59:27 +1000 Subject: [PATCH 140/219] Remove unused methods --- .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 144 ------------------ .../SimdUtils.FallbackIntrinsics128.cs | 61 -------- .../ImageSharp.Benchmarks/Bulk/FromVector4.cs | 18 --- .../Bulk/ToVector4_Rgba32.cs | 9 -- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 18 --- 5 files changed, 250 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs index 7d07dcaaed..3c2f189cf6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs @@ -3,7 +3,6 @@ using System.Numerics; using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; // ReSharper disable MemberHidesStaticFromOuterClass namespace SixLabors.ImageSharp; @@ -35,148 +34,5 @@ internal static partial class SimdUtils dest1 = Vector.ConvertToSingle(i1); dest2 = Vector.ConvertToSingle(i2); } - - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloatReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - if (!IsAvailable) - { - return; - } - - int remainder = Numerics.ModuloP2(source.Length, Vector.Count); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturateReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - if (!IsAvailable) - { - return; - } - - int remainder = Numerics.ModuloP2(source.Length, Vector.Count); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - NormalizedFloatToByteSaturate(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// Implementation , which is faster on new RyuJIT runtime. - /// - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - DebugVerifySpanInput(source, dest, Vector.Count); - - nuint n = dest.VectorCount(); - - ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - for (nuint i = 0; i < n; i++) - { - Vector b = Unsafe.Add(ref sourceBase, i); - - Vector.Widen(b, out Vector s0, out Vector s1); - Vector.Widen(s0, out Vector w0, out Vector w1); - Vector.Widen(s1, out Vector w2, out Vector w3); - - Vector f0 = ConvertToSingle(w0); - Vector f1 = ConvertToSingle(w1); - Vector f2 = ConvertToSingle(w2); - Vector f3 = ConvertToSingle(w3); - - ref Vector d = ref Unsafe.Add(ref destBase, i * 4); - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } - } - - /// - /// Implementation of , which is faster on new .NET runtime. - /// - internal static void NormalizedFloatToByteSaturate( - ReadOnlySpan source, - Span dest) - { - DebugVerifySpanInput(source, dest, Vector.Count); - - nuint n = dest.VectorCount(); - - ref Vector sourceBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(source)); - ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); - - for (nuint i = 0; i < n; i++) - { - ref Vector s = ref Unsafe.Add(ref sourceBase, i * 4); - - Vector f0 = s; - Vector f1 = Unsafe.Add(ref s, 1); - Vector f2 = Unsafe.Add(ref s, 2); - Vector f3 = Unsafe.Add(ref s, 3); - - Vector w0 = ConvertToUInt32(f0); - Vector w1 = ConvertToUInt32(f1); - Vector w2 = ConvertToUInt32(f2); - Vector w3 = ConvertToUInt32(f3); - - var u0 = Vector.Narrow(w0, w1); - var u1 = Vector.Narrow(w2, w3); - - Unsafe.Add(ref destBase, i) = Vector.Narrow(u0, u1); - } - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToUInt32(Vector vf) - { - var maxBytes = new Vector(255f); - vf *= maxBytes; - vf += new Vector(0.5f); - vf = Vector.Min(Vector.Max(vf, Vector.Zero), maxBytes); - var vi = Vector.ConvertToInt32(vf); - return Vector.AsVectorUInt32(vi); - } - - [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static Vector ConvertToSingle(Vector u) - { - var vi = Vector.AsVectorInt32(u); - var v = Vector.ConvertToSingle(vi); - v *= new Vector(1f / 255f); - return v; - } } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs index 90b313fb90..fcf441c476 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs @@ -39,30 +39,6 @@ internal static partial class SimdUtils } } - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturateReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - int remainder = Numerics.Modulo4(source.Length); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - NormalizedFloatToByteSaturate( - source[..adjustedCount], - dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - /// /// Implementation of using . /// @@ -95,43 +71,6 @@ internal static partial class SimdUtils } } - /// - /// Implementation of using . - /// - [MethodImpl(InliningOptions.ColdPath)] - internal static void NormalizedFloatToByteSaturate( - ReadOnlySpan source, - Span dest) - { - DebugVerifySpanInput(source, dest, 4); - - uint count = (uint)source.Length / 4; - if (count == 0) - { - return; - } - - ref Vector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref ByteVector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - var half = new Vector4(0.5f); - var maxBytes = new Vector4(255f); - - for (nuint i = 0; i < count; i++) - { - Vector4 s = Unsafe.Add(ref sBase, i); - s *= maxBytes; - s += half; - s = Numerics.Clamp(s, Vector4.Zero, maxBytes); - - ref ByteVector4 d = ref Unsafe.Add(ref dBase, i); - d.X = (byte)s.X; - d.Y = (byte)s.Y; - d.Z = (byte)s.Z; - d.W = (byte)s.W; - } - } - [StructLayout(LayoutKind.Sequential)] private struct ByteVector4 { diff --git a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs index dff687fa12..53c26a57ea 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/FromVector4.cs @@ -64,24 +64,6 @@ public abstract class FromVector4 public class FromVector4Rgba32 : FromVector4 { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(sBytes, dFloats); - } - - [Benchmark] - public void ExtendedIntrinsic() - { - Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(sBytes, dFloats); - } - [Benchmark] public void UseHwIntrinsics() { diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs index 1ceae84140..9c7ecbc491 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs @@ -30,15 +30,6 @@ public class ToVector4_Rgba32 : ToVector4 this.source.GetSpan(), this.destination.GetSpan()); - [Benchmark] - public void ExtendedIntrinsics() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(sBytes, dFloats); - } - [Benchmark] public void HwIntrinsics() { diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index 2003716796..e9e4550b04 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -122,12 +122,6 @@ public partial class SimdUtilsTests count, (s, d) => SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(s.Span, d.Span)); - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] - public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat( - count, - (s, d) => SimdUtils.ExtendedIntrinsics.ByteToNormalizedFloat(s.Span, d.Span)); - [Theory] [MemberData(nameof(ArraySizesDivisibleBy32))] public void HwIntrinsics_BulkConvertByteToNormalizedFloat(int count) @@ -166,18 +160,6 @@ public partial class SimdUtilsTests Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy4))] - public void FallbackIntrinsics128_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( - count, - (s, d) => SimdUtils.FallbackIntrinsics128.NormalizedFloatToByteSaturate(s.Span, d.Span)); - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] - public void ExtendedIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) => TestImpl_BulkConvertNormalizedFloatToByteClampOverflows( - count, - (s, d) => SimdUtils.ExtendedIntrinsics.NormalizedFloatToByteSaturate(s.Span, d.Span)); - [Theory] [InlineData(1234)] public void ExtendedIntrinsics_ConvertToSingle(short scale) From 68b7dbcf58d7a944197a78bd40236c9d4057840b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Feb 2024 19:48:20 +1000 Subject: [PATCH 141/219] Update src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs Co-authored-by: Clinton Ingram --- src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index feb55ebe59..df844582a6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -49,10 +49,7 @@ internal static partial class SimdUtils 0, 1, 2, 4, 5, 6, 8, 9, 10, 12, 13, 14, 3, 7, 11, 15); [MethodImpl(MethodImplOptions.AggressiveInlining)] - public static Vector256 PermuteMaskShiftAlpha8x32() - => Vector256.Create( - 0, 0, 0, 0, 1, 0, 0, 0, 2, 0, 0, 0, 4, 0, 0, 0, - 5, 0, 0, 0, 6, 0, 0, 0, 3, 0, 0, 0, 7, 0, 0, 0).AsUInt32(); + public static Vector256 PermuteMaskShiftAlpha8x32() => Vector256.Create(0u, 1, 2, 4, 5, 6, 3, 7); #pragma warning restore SA1137 // Elements should have the same indentation #pragma warning restore SA1117 // Parameters should be on same line or separate lines From 9d737b71f758bd764e68c562db9e3a0d72221b21 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 2 Feb 2024 19:51:01 +1000 Subject: [PATCH 142/219] Avoid downclocking --- src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index feb55ebe59..f5fa73cf0f 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -896,7 +896,9 @@ internal static partial class SimdUtils { DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if (Avx512BW.IsSupported || Avx2.IsSupported || Sse2.IsSupported || AdvSimd.IsSupported) + if ((Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) || + (Vector256.IsHardwareAccelerated && Avx2.IsSupported) || + (Vector128.IsHardwareAccelerated && (Sse2.IsSupported || AdvSimd.IsSupported))) { int remainder; From ecdd12e7b58ae6ef01947b849f844ca7e5b0b254 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Mon, 5 Feb 2024 09:10:56 +0000 Subject: [PATCH 143/219] Bump codecov/codecov-action from 3 to 4 Bumps [codecov/codecov-action](https://github.com/codecov/codecov-action) from 3 to 4. - [Release notes](https://github.com/codecov/codecov-action/releases) - [Changelog](https://github.com/codecov/codecov-action/blob/main/CHANGELOG.md) - [Commits](https://github.com/codecov/codecov-action/compare/v3...v4) --- updated-dependencies: - dependency-name: codecov/codecov-action dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/code-coverage.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 62b6477ee6..19a9689ce2 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -81,7 +81,7 @@ jobs: path: tests/Images/ActualOutput/ - name: Codecov Update - uses: codecov/codecov-action@v3 + uses: codecov/codecov-action@v4 if: matrix.options.codecov == true && startsWith(github.repository, 'SixLabors') with: flags: unittests From c6758df08b193cca5243ec030db5305c0846c3dd Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 6 Feb 2024 16:22:50 +1000 Subject: [PATCH 144/219] Optimize and cleanup ByteToNormalizedFloatReduce --- src/ImageSharp/Common/Helpers/Numerics.cs | 20 ++ .../Common/Helpers/SimdUtils.Convert.cs | 77 +++++++ .../Helpers/SimdUtils.ExtendedIntrinsics.cs | 38 ---- .../SimdUtils.FallbackIntrinsics128.cs | 83 -------- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 190 +++++++++++------- src/ImageSharp/Common/Helpers/SimdUtils.cs | 97 --------- .../Common/Helpers/Vector128Utilities.cs | 13 +- .../Formats/Jpeg/Components/Block8x8F.cs | 42 ++-- .../Utils/Vector4Converters.RgbaCompatible.cs | 75 ++++--- tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs | 25 +-- .../Bulk/ToVector4_Bgra32.cs | 4 +- .../Bulk/ToVector4_Rgb24.cs | 4 +- .../Bulk/ToVector4_Rgba32.cs | 63 +++--- .../LoadResizeSave/README.md | 2 +- .../ImageSharp.Tests/Common/SimdUtilsTests.cs | 36 +--- 15 files changed, 344 insertions(+), 425 deletions(-) create mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs delete mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs delete mode 100644 src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs diff --git a/src/ImageSharp/Common/Helpers/Numerics.cs b/src/ImageSharp/Common/Helpers/Numerics.cs index 5f85734e83..777de2dc9f 100644 --- a/src/ImageSharp/Common/Helpers/Numerics.cs +++ b/src/ImageSharp/Common/Helpers/Numerics.cs @@ -1069,4 +1069,24 @@ internal static class Numerics public static nuint Vector256Count(int length) where TVector : struct => (uint)length / (uint)Vector256.Count; + + /// + /// Gets the count of vectors that safely fit into the given span. + /// + /// The type of the vector. + /// The given span. + /// Count of vectors that safely fit into the span. + public static nuint Vector512Count(this Span span) + where TVector : struct + => (uint)span.Length / (uint)Vector512.Count; + + /// + /// Gets the count of vectors that safely fit into length. + /// + /// The type of the vector. + /// The given length. + /// Count of vectors that safely fit into the length. + public static nuint Vector512Count(int length) + where TVector : struct + => (uint)length / (uint)Vector512.Count; } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs new file mode 100644 index 0000000000..1b5a418dea --- /dev/null +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs @@ -0,0 +1,77 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +using System.Runtime.CompilerServices; +using System.Runtime.InteropServices; + +namespace SixLabors.ImageSharp; + +internal static partial class SimdUtils +{ + /// + /// Converts all input -s to -s normalized into [0..1]. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of bytes + /// The destination span of floats + [MethodImpl(InliningOptions.ShortMethod)] + internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span destination) + { + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); + + HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref destination); + + if (source.Length > 0) + { + ConvertByteToNormalizedFloatRemainder(source, destination); + } + } + + /// + /// Convert all values normalized into [0..1] from 'source' into 'destination' buffer of . + /// The values are scaled up into [0-255] and rounded, overflows are clamped. + /// should be the of the same size as , + /// but there are no restrictions on the span's length. + /// + /// The source span of floats + /// The destination span of bytes + [MethodImpl(InliningOptions.ShortMethod)] + internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span destination) + { + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); + + HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref destination); + + if (source.Length > 0) + { + ConvertNormalizedFloatToByteRemainder(source, destination); + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span destination) + { + ref byte sBase = ref MemoryMarshal.GetReference(source); + ref float dBase = ref MemoryMarshal.GetReference(destination); + + for (int i = 0; i < source.Length; i++) + { + Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; + } + } + + [MethodImpl(MethodImplOptions.NoInlining)] + private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span destination) + { + ref float sBase = ref MemoryMarshal.GetReference(source); + ref byte dBase = ref MemoryMarshal.GetReference(destination); + for (int i = 0; i < source.Length; i++) + { + Unsafe.Add(ref dBase, i) = ConvertToByte(Unsafe.Add(ref sBase, i)); + } + } + + [MethodImpl(MethodImplOptions.AggressiveInlining)] + private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255F) + 0.5F, 0, 255F); +} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs deleted file mode 100644 index 3c2f189cf6..0000000000 --- a/src/ImageSharp/Common/Helpers/SimdUtils.ExtendedIntrinsics.cs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; - -// ReSharper disable MemberHidesStaticFromOuterClass -namespace SixLabors.ImageSharp; - -internal static partial class SimdUtils -{ - /// - /// Implementation methods based on newer API-s (Vector.Widen, Vector.Narrow, Vector.ConvertTo*). - /// Only accelerated only on RyuJIT having dotnet/coreclr#10662 merged (.NET Core 2.1+ .NET 4.7.2+) - /// See: - /// https://github.com/dotnet/coreclr/pull/10662 - /// API Proposal: - /// https://github.com/dotnet/corefx/issues/15957 - /// - public static class ExtendedIntrinsics - { - public static bool IsAvailable { get; } = Vector.IsHardwareAccelerated; - - /// - /// Widen and convert a vector of values into 2 vectors of -s. - /// - [MethodImpl(MethodImplOptions.AggressiveInlining)] - internal static void ConvertToSingle( - Vector source, - out Vector dest1, - out Vector dest2) - { - Vector.Widen(source, out Vector i1, out Vector i2); - dest1 = Vector.ConvertToSingle(i1); - dest2 = Vector.ConvertToSingle(i2); - } - } -} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs b/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs deleted file mode 100644 index fcf441c476..0000000000 --- a/src/ImageSharp/Common/Helpers/SimdUtils.FallbackIntrinsics128.cs +++ /dev/null @@ -1,83 +0,0 @@ -// Copyright (c) Six Labors. -// Licensed under the Six Labors Split License. - -using System.Numerics; -using System.Runtime.CompilerServices; -using System.Runtime.InteropServices; - -// ReSharper disable MemberHidesStaticFromOuterClass -namespace SixLabors.ImageSharp; - -internal static partial class SimdUtils -{ - /// - /// Fallback implementation based on (128bit). - /// For , efficient software fallback implementations are present, - /// and we hope that even mono's JIT is able to emit SIMD instructions for that type :P - /// - public static class FallbackIntrinsics128 - { - /// - /// as many elements as possible, slicing them down (keeping the remainder). - /// - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloatReduce( - ref ReadOnlySpan source, - ref Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - int remainder = Numerics.Modulo4(source.Length); - int adjustedCount = source.Length - remainder; - - if (adjustedCount > 0) - { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); - - source = source[adjustedCount..]; - dest = dest[adjustedCount..]; - } - } - - /// - /// Implementation of using . - /// - [MethodImpl(InliningOptions.ColdPath)] - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - DebugVerifySpanInput(source, dest, 4); - - uint count = (uint)dest.Length / 4; - if (count == 0) - { - return; - } - - ref ByteVector4 sBase = ref Unsafe.As(ref MemoryMarshal.GetReference(source)); - ref Vector4 dBase = ref Unsafe.As(ref MemoryMarshal.GetReference(dest)); - - const float scale = 1f / 255f; - Vector4 d = default; - - for (nuint i = 0; i < count; i++) - { - ref ByteVector4 s = ref Unsafe.Add(ref sBase, i); - d.X = s.X; - d.Y = s.Y; - d.Z = s.Z; - d.W = s.W; - d *= scale; - Unsafe.Add(ref dBase, i) = d; - } - } - - [StructLayout(LayoutKind.Sequential)] - private struct ByteVector4 - { - public byte X; - public byte Y; - public byte Z; - public byte W; - } - } -} diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 487331360c..6f0b4b4e3c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -752,17 +752,23 @@ internal static partial class SimdUtils /// /// as many elements as possible, slicing them down (keeping the remainder). /// + /// The source buffer. + /// The destination buffer. [MethodImpl(InliningOptions.ShortMethod)] internal static void ByteToNormalizedFloatReduce( ref ReadOnlySpan source, - ref Span dest) + ref Span destination) { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); + DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); if (Avx2.IsSupported || Sse2.IsSupported) { int remainder; - if (Avx2.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) + { + remainder = Numerics.ModuloP2(source.Length, Vector512.Count); + } + else if (Avx2.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector256.Count); } @@ -775,10 +781,10 @@ internal static partial class SimdUtils if (adjustedCount > 0) { - ByteToNormalizedFloat(source[..adjustedCount], dest[..adjustedCount]); + ByteToNormalizedFloat(source[..adjustedCount], destination[..adjustedCount]); source = source[adjustedCount..]; - dest = dest[adjustedCount..]; + destination = destination[adjustedCount..]; } } } @@ -786,97 +792,127 @@ internal static partial class SimdUtils /// /// Implementation , which is faster on new RyuJIT runtime. /// + /// The source buffer. + /// The destination buffer. /// /// Implementation is based on MagicScaler code: /// https://github.com/saucecontrol/PhotoSauce/blob/b5811908041200488aa18fdfd17df5fc457415dc/src/MagicScaler/Magic/Processors/ConvertersFloat.cs#L80-L182 /// internal static unsafe void ByteToNormalizedFloat( ReadOnlySpan source, - Span dest) + Span destination) { - fixed (byte* sourceBase = source) + if (Avx512F.IsSupported) { - if (Avx2.IsSupported) - { - DebugVerifySpanInput(source, dest, Vector256.Count); - - nuint n = dest.Vector256Count(); + DebugVerifySpanInput(source, destination, Vector512.Count); - ref Vector256 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + nuint n = destination.Vector512Count(); - Vector256 scale = Vector256.Create(1 / (float)byte.MaxValue); + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector512 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - for (nuint i = 0; i < n; i++) - { - nuint si = (uint)Vector256.Count * i; - Vector256 i0 = Avx2.ConvertToVector256Int32(sourceBase + si); - Vector256 i1 = Avx2.ConvertToVector256Int32(sourceBase + si + Vector256.Count); - Vector256 i2 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 2)); - Vector256 i3 = Avx2.ConvertToVector256Int32(sourceBase + si + (Vector256.Count * 3)); - - Vector256 f0 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i0)); - Vector256 f1 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i1)); - Vector256 f2 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i2)); - Vector256 f3 = Avx.Multiply(scale, Avx.ConvertToVector256Single(i3)); - - ref Vector256 d = ref Unsafe.Add(ref destBase, i * 4); - - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; - } + for (nuint i = 0; i < n; i++) + { + nuint si = (uint)Vector512.Count * i; + Vector512 i0 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si)); + Vector512 i1 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)Vector512.Count)); + Vector512 i2 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector512.Count * 2))); + Vector512 i3 = Avx512F.ConvertToVector512Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector512.Count * 3))); + + // Declare multiplier on each line. Codegen is better. + Vector512 f0 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i0); + Vector512 f1 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i1); + Vector512 f2 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i2); + Vector512 f3 = Vector512.Create(1 / (float)byte.MaxValue) * Avx512F.ConvertToVector512Single(i3); + + ref Vector512 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } - else + } + else if (Avx2.IsSupported) + { + DebugVerifySpanInput(source, destination, Vector256.Count); + + nuint n = destination.Vector256Count(); + + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector256 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); + + for (nuint i = 0; i < n; i++) { - // Sse - DebugVerifySpanInput(source, dest, Vector128.Count); + nuint si = (uint)Vector256.Count * i; + Vector256 i0 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si)); + Vector256 i1 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)Vector256.Count)); + Vector256 i2 = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sourceBase, si + (nuint)(Vector256.Count * 2))); + + // Ensure overreads past 16 byte boundary do not happen in debug due to lack of containment. + ref ulong refULong = ref Unsafe.As(ref Unsafe.Add(ref sourceBase, si)); + Vector256 i3 = Avx2.ConvertToVector256Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refULong, 3)).AsByte()); + + // Declare multiplier on each line. Codegen is better. + Vector256 f0 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i0); + Vector256 f1 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i1); + Vector256 f2 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i2); + Vector256 f3 = Vector256.Create(1 / (float)byte.MaxValue) * Avx.ConvertToVector256Single(i3); + + ref Vector256 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; + } + } + else if (Sse2.IsSupported || AdvSimd.IsSupported) + { + DebugVerifySpanInput(source, destination, Vector128.Count); - nuint n = dest.Vector128Count(); + nuint n = destination.Vector128Count(); + + ref byte sourceBase = ref MemoryMarshal.GetReference(source); + ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); - ref Vector128 destBase = - ref Unsafe.As>(ref MemoryMarshal.GetReference(dest)); + Vector128 scale = Vector128.Create(1 / (float)byte.MaxValue); + Vector128 zero = Vector128.Zero; - Vector128 scale = Vector128.Create(1 / (float)byte.MaxValue); - Vector128 zero = Vector128.Zero; + for (nuint i = 0; i < n; i++) + { + nuint si = (uint)Vector128.Count * i; - for (nuint i = 0; i < n; i++) + Vector128 i0, i1, i2, i3; + if (Sse41.IsSupported) { - nuint si = (uint)Vector128.Count * i; - - Vector128 i0, i1, i2, i3; - if (Sse41.IsSupported) - { - i0 = Sse41.ConvertToVector128Int32(sourceBase + si); - i1 = Sse41.ConvertToVector128Int32(sourceBase + si + Vector128.Count); - i2 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 2)); - i3 = Sse41.ConvertToVector128Int32(sourceBase + si + (Vector128.Count * 3)); - } - else - { - Vector128 b = Sse2.LoadVector128(sourceBase + si); - Vector128 s0 = Sse2.UnpackLow(b, zero).AsInt16(); - Vector128 s1 = Sse2.UnpackHigh(b, zero).AsInt16(); - - i0 = Sse2.UnpackLow(s0, zero.AsInt16()).AsInt32(); - i1 = Sse2.UnpackHigh(s0, zero.AsInt16()).AsInt32(); - i2 = Sse2.UnpackLow(s1, zero.AsInt16()).AsInt32(); - i3 = Sse2.UnpackHigh(s1, zero.AsInt16()).AsInt32(); - } - - Vector128 f0 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i0)); - Vector128 f1 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i1)); - Vector128 f2 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i2)); - Vector128 f3 = Sse.Multiply(scale, Sse2.ConvertToVector128Single(i3)); - - ref Vector128 d = ref Unsafe.Add(ref destBase, i * 4); - - d = f0; - Unsafe.Add(ref d, 1) = f1; - Unsafe.Add(ref d, 2) = f2; - Unsafe.Add(ref d, 3) = f3; + ref int refInt = ref Unsafe.As(ref Unsafe.Add(ref sourceBase, si)); + + i0 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(refInt).AsByte()); + i1 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 1)).AsByte()); + i2 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 2)).AsByte()); + i3 = Sse41.ConvertToVector128Int32(Vector128.CreateScalarUnsafe(Unsafe.Add(ref refInt, 3)).AsByte()); } + else + { + // Sse2, AdvSimd + Vector128 b = Vector128.LoadUnsafe(ref sourceBase, si); + (Vector128 s0, Vector128 s1) = Vector128.Widen(b); + (i0, i1) = Vector128.Widen(s0.AsInt16()); + (i2, i3) = Vector128.Widen(s1.AsInt16()); + } + + Vector128 f0 = scale * Vector128.ConvertToSingle(i0); + Vector128 f1 = scale * Vector128.ConvertToSingle(i1); + Vector128 f2 = scale * Vector128.ConvertToSingle(i2); + Vector128 f3 = scale * Vector128.ConvertToSingle(i3); + + ref Vector128 d = ref Unsafe.Add(ref destinationBase, i * 4); + + d = f0; + Unsafe.Add(ref d, 1) = f1; + Unsafe.Add(ref d, 2) = f2; + Unsafe.Add(ref d, 3) = f3; } } } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.cs b/src/ImageSharp/Common/Helpers/SimdUtils.cs index 002c1f8da0..0279e57cc6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.cs @@ -22,13 +22,6 @@ internal static partial class SimdUtils public static bool HasVector8 { get; } = Vector.IsHardwareAccelerated && Vector.Count == 8 && Vector.Count == 8; - /// - /// Gets a value indicating whether code is being JIT-ed to SSE instructions - /// where float and integer registers are of size 128 byte. - /// - public static bool HasVector4 { get; } = - Vector.IsHardwareAccelerated && Vector.Count == 4; - /// /// Transform all scalars in 'v' in a way that converting them to would have rounding semantics. /// @@ -69,96 +62,6 @@ internal static partial class SimdUtils } } - /// - /// Converts all input -s to -s normalized into [0..1]. - /// should be the of the same size as , - /// but there are no restrictions on the span's length. - /// - /// The source span of bytes - /// The destination span of floats - [MethodImpl(InliningOptions.ShortMethod)] - internal static void ByteToNormalizedFloat(ReadOnlySpan source, Span dest) - { - DebugGuard.IsTrue(source.Length == dest.Length, nameof(source), "Input spans must be of same length!"); - - HwIntrinsics.ByteToNormalizedFloatReduce(ref source, ref dest); - - // Also deals with the remainder from previous conversions: - FallbackIntrinsics128.ByteToNormalizedFloatReduce(ref source, ref dest); - - // Deal with the remainder: - if (source.Length > 0) - { - ConvertByteToNormalizedFloatRemainder(source, dest); - } - } - - /// - /// Convert all values normalized into [0..1] from 'source' into 'destination' buffer of . - /// The values are scaled up into [0-255] and rounded, overflows are clamped. - /// should be the of the same size as , - /// but there are no restrictions on the span's length. - /// - /// The source span of floats - /// The destination span of bytes - [MethodImpl(InliningOptions.ShortMethod)] - internal static void NormalizedFloatToByteSaturate(ReadOnlySpan source, Span destination) - { - DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - HwIntrinsics.NormalizedFloatToByteSaturateReduce(ref source, ref destination); - - // Deal with the remainder: - if (source.Length > 0) - { - ConvertNormalizedFloatToByteRemainder(source, destination); - } - } - - [MethodImpl(InliningOptions.ColdPath)] - private static void ConvertByteToNormalizedFloatRemainder(ReadOnlySpan source, Span destination) - { - ref byte sBase = ref MemoryMarshal.GetReference(source); - ref float dBase = ref MemoryMarshal.GetReference(destination); - - // There are at most 3 elements at this point, having a for loop is overkill. - // Let's minimize the no. of instructions! - switch (source.Length) - { - case 3: - Unsafe.Add(ref dBase, 2) = Unsafe.Add(ref sBase, 2) / 255f; - goto case 2; - case 2: - Unsafe.Add(ref dBase, 1) = Unsafe.Add(ref sBase, 1) / 255f; - goto case 1; - case 1: - dBase = sBase / 255f; - break; - } - } - - [MethodImpl(MethodImplOptions.NoInlining)] - private static void ConvertNormalizedFloatToByteRemainder(ReadOnlySpan source, Span destination) - { - ref float sBase = ref MemoryMarshal.GetReference(source); - ref byte dBase = ref MemoryMarshal.GetReference(destination); - for (int i = 0; i < source.Length; i++) - { - Unsafe.Add(ref dBase, i) = ConvertToByte(Unsafe.Add(ref sBase, i)); - } - } - - [MethodImpl(InliningOptions.ShortMethod)] - private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255F) + 0.5F, 0, 255F); - - [Conditional("DEBUG")] - private static void VerifyHasVector8(string operation) - { - if (!HasVector8) - { - throw new NotSupportedException($"{operation} is supported only on AVX2 CPU!"); - } - } - [Conditional("DEBUG")] private static void DebugVerifySpanInput(ReadOnlySpan source, Span dest, int shouldBeDivisibleBy) { diff --git a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs index a07fa8ca6e..b6dd319f06 100644 --- a/src/ImageSharp/Common/Helpers/Vector128Utilities.cs +++ b/src/ImageSharp/Common/Helpers/Vector128Utilities.cs @@ -26,7 +26,7 @@ internal static class Vector128Utilities public static bool SupportsShuffleFloat { [MethodImpl(MethodImplOptions.AggressiveInlining)] - get => Sse.IsSupported || AdvSimd.IsSupported; + get => Sse.IsSupported; } /// @@ -70,17 +70,6 @@ internal static class Vector128Utilities return Sse.Shuffle(vector, vector, control); } - if (AdvSimd.IsSupported) - { -#pragma warning disable CA1857 // A constant is expected for the parameter - Vector128 result = Vector128.Create(AdvSimd.Extract(vector, (byte)(control & 0x3))); - result = AdvSimd.Insert(result, 1, AdvSimd.Extract(vector, (byte)((control >> 2) & 0x3))); - result = AdvSimd.Insert(result, 2, AdvSimd.Extract(vector, (byte)((control >> 4) & 0x3))); - result = AdvSimd.Insert(result, 3, AdvSimd.Extract(vector, (byte)((control >> 6) & 0x3))); -#pragma warning restore CA1857 // A constant is expected for the parameter - return result; - } - ThrowUnreachableException(); return default; } diff --git a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs index d432e82d24..018df5f9f4 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Block8x8F.cs @@ -386,29 +386,33 @@ internal partial struct Block8x8F : IEquatable public void LoadFromInt16ExtendedAvx2(ref Block8x8 source) { DebugGuard.IsTrue( - SimdUtils.HasVector8, + Avx2.IsSupported, "LoadFromUInt16ExtendedAvx2 only works on AVX2 compatible architecture!"); - ref Vector sRef = ref Unsafe.As>(ref source); - ref Vector dRef = ref Unsafe.As>(ref this); + ref short sRef = ref Unsafe.As(ref source); + ref Vector256 dRef = ref Unsafe.As>(ref this); - // Vector.Count == 16 on AVX2 + // Vector256.Count == 16 on AVX2 // We can process 2 block rows in a single step - SimdUtils.ExtendedIntrinsics.ConvertToSingle(sRef, out Vector top, out Vector bottom); - dRef = top; - Unsafe.Add(ref dRef, 1) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 1), out top, out bottom); - Unsafe.Add(ref dRef, 2) = top; - Unsafe.Add(ref dRef, 3) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 2), out top, out bottom); - Unsafe.Add(ref dRef, 4) = top; - Unsafe.Add(ref dRef, 5) = bottom; - - SimdUtils.ExtendedIntrinsics.ConvertToSingle(Unsafe.Add(ref sRef, 3), out top, out bottom); - Unsafe.Add(ref dRef, 6) = top; - Unsafe.Add(ref dRef, 7) = bottom; + Vector256 top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef)); + Vector256 bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)Vector256.Count)); + dRef = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 1) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 2))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 3))); + Unsafe.Add(ref dRef, 2) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 3) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 4))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 5))); + Unsafe.Add(ref dRef, 4) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 5) = Avx.ConvertToVector256Single(bottom); + + top = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 6))); + bottom = Avx2.ConvertToVector256Int32(Vector128.LoadUnsafe(ref sRef, (nuint)(Vector256.Count * 7))); + Unsafe.Add(ref dRef, 6) = Avx.ConvertToVector256Single(top); + Unsafe.Add(ref dRef, 7) = Avx.ConvertToVector256Single(bottom); } /// diff --git a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs index 8616ecb3b1..9e649f3c08 100644 --- a/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs +++ b/src/ImageSharp/PixelFormats/Utils/Vector4Converters.RgbaCompatible.cs @@ -5,6 +5,7 @@ using System.Buffers; using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; +using System.Runtime.Intrinsics; namespace SixLabors.ImageSharp.PixelFormats.Utils; @@ -31,74 +32,86 @@ internal static partial class Vector4Converters /// Provides an efficient default implementation for /// The method works by internally converting to a therefore it's not applicable for that type! /// - [MethodImpl(InliningOptions.ShortMethod)] + /// The type of pixel format. + /// The configuration. + /// The pixel operations instance. + /// The source buffer. + /// The destination buffer. + /// The conversion modifier flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void ToVector4( Configuration configuration, PixelOperations pixelOperations, - ReadOnlySpan sourcePixels, - Span destVectors, + ReadOnlySpan source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourcePixels, destVectors, nameof(destVectors)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = sourcePixels.Length; + int count = source.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { - Default.UnsafeToVector4(sourcePixels, destVectors, modifiers); + Default.UnsafeToVector4(source, destination, modifiers); return; } - // Using the last quarter of 'destVectors' as a temporary buffer to avoid allocation: + // Using the last quarter of 'destination' as a temporary buffer to avoid allocation: int countWithoutLastItem = count - 1; - ReadOnlySpan reducedSource = sourcePixels[..countWithoutLastItem]; - Span lastQuarterOfDestBuffer = MemoryMarshal.Cast(destVectors).Slice((3 * count) + 1, countWithoutLastItem); - pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestBuffer); + ReadOnlySpan reducedSource = source[..countWithoutLastItem]; + Span lastQuarterOfDestination = MemoryMarshal.Cast(destination).Slice((3 * count) + 1, countWithoutLastItem); + pixelOperations.ToRgba32(configuration, reducedSource, lastQuarterOfDestination); - // 'destVectors' and 'lastQuarterOfDestBuffer' are overlapping buffers, + // 'destination' and 'lastQuarterOfDestination' are overlapping buffers, // but we are always reading/writing at different positions: SimdUtils.ByteToNormalizedFloat( - MemoryMarshal.Cast(lastQuarterOfDestBuffer), - MemoryMarshal.Cast(destVectors[..countWithoutLastItem])); + MemoryMarshal.Cast(lastQuarterOfDestination), + MemoryMarshal.Cast(destination[..countWithoutLastItem])); - destVectors[countWithoutLastItem] = sourcePixels[countWithoutLastItem].ToVector4(); + destination[countWithoutLastItem] = source[countWithoutLastItem].ToVector4(); // TODO: Investigate optimized 1-pass approach! - ApplyForwardConversionModifiers(destVectors, modifiers); + ApplyForwardConversionModifiers(destination, modifiers); } /// /// Provides an efficient default implementation for /// The method is works by internally converting to a therefore it's not applicable for that type! /// - [MethodImpl(InliningOptions.ShortMethod)] + /// The type of pixel format. + /// The configuration. + /// The pixel operations instance. + /// The source buffer. + /// The destination buffer. + /// The conversion modifier flags. + [MethodImpl(MethodImplOptions.AggressiveInlining)] internal static void FromVector4( Configuration configuration, PixelOperations pixelOperations, - Span sourceVectors, - Span destPixels, + Span source, + Span destination, PixelConversionModifiers modifiers) where TPixel : unmanaged, IPixel { Guard.NotNull(configuration, nameof(configuration)); - Guard.DestinationShouldNotBeTooShort(sourceVectors, destPixels, nameof(destPixels)); + Guard.DestinationShouldNotBeTooShort(source, destination, nameof(destination)); - int count = sourceVectors.Length; + int count = source.Length; // Not worth for small buffers: if (count < Vector4ConversionThreshold) { - Default.UnsafeFromVector4(sourceVectors, destPixels, modifiers); + Default.UnsafeFromVector4(source, destination, modifiers); return; } // TODO: Investigate optimized 1-pass approach! - ApplyBackwardConversionModifiers(sourceVectors, modifiers); + ApplyBackwardConversionModifiers(source, modifiers); // For the opposite direction it's not easy to implement the trick used in RunRgba32CompatibleToVector4Conversion, // so let's allocate a temporary buffer as usually: @@ -106,20 +119,30 @@ internal static partial class Vector4Converters Span tempSpan = tempBuffer.Memory.Span; SimdUtils.NormalizedFloatToByteSaturate( - MemoryMarshal.Cast(sourceVectors), + MemoryMarshal.Cast(source), MemoryMarshal.Cast(tempSpan)); - pixelOperations.FromRgba32(configuration, tempSpan, destPixels); + pixelOperations.FromRgba32(configuration, tempSpan, destination); } private static int CalculateVector4ConversionThreshold() { - if (!Vector.IsHardwareAccelerated) + if (!Vector128.IsHardwareAccelerated) { return int.MaxValue; } - return SimdUtils.ExtendedIntrinsics.IsAvailable && SimdUtils.HasVector8 ? 256 : 128; + if (Vector512.IsHardwareAccelerated) + { + return 512; + } + + if (Vector256.IsHardwareAccelerated) + { + return 256; + } + + return 128; } } } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs index 3b4360b161..0df8d9818c 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4.cs @@ -14,9 +14,9 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; public abstract class ToVector4 where TPixel : unmanaged, IPixel { - protected IMemoryOwner source; + protected IMemoryOwner Source { get; set; } - protected IMemoryOwner destination; + protected IMemoryOwner Destination { get; set; } protected Configuration Configuration => Configuration.Default; @@ -26,22 +26,22 @@ public abstract class ToVector4 [GlobalSetup] public void Setup() { - this.source = this.Configuration.MemoryAllocator.Allocate(this.Count); - this.destination = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Source = this.Configuration.MemoryAllocator.Allocate(this.Count); + this.Destination = this.Configuration.MemoryAllocator.Allocate(this.Count); } [GlobalCleanup] public void Cleanup() { - this.source.Dispose(); - this.destination.Dispose(); + this.Source.Dispose(); + this.Destination.Dispose(); } // [Benchmark] public void Naive() { - Span s = this.source.GetSpan(); - Span d = this.destination.GetSpan(); + Span s = this.Source.GetSpan(); + Span d = this.Destination.GetSpan(); for (int i = 0; i < this.Count; i++) { @@ -50,11 +50,8 @@ public abstract class ToVector4 } [Benchmark] - public void PixelOperations_Specialized() - { - PixelOperations.Instance.ToVector4( + public void PixelOperations_Specialized() => PixelOperations.Instance.ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); - } + this.Source.GetSpan(), + this.Destination.GetSpan()); } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs index 934a17dc94..6499632b69 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Bgra32.cs @@ -16,8 +16,8 @@ public class ToVector4_Bgra32 : ToVector4 { new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); + this.Source.GetSpan(), + this.Destination.GetSpan()); } // RESULTS: diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs index d5d6e31b5d..adedabf8f5 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgb24.cs @@ -16,8 +16,8 @@ public class ToVector4_Rgb24 : ToVector4 { new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); + this.Source.GetSpan(), + this.Destination.GetSpan()); } } diff --git a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs index 9c7ecbc491..113793a033 100644 --- a/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs +++ b/tests/ImageSharp.Benchmarks/Bulk/ToVector4_Rgba32.cs @@ -14,27 +14,18 @@ namespace SixLabors.ImageSharp.Benchmarks.Bulk; [Config(typeof(Config.Short))] public class ToVector4_Rgba32 : ToVector4 { - [Benchmark] - public void FallbackIntrinsics128() - { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); - - SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(sBytes, dFloats); - } - [Benchmark] public void PixelOperations_Base() => new PixelOperations().ToVector4( this.Configuration, - this.source.GetSpan(), - this.destination.GetSpan()); + this.Source.GetSpan(), + this.Destination.GetSpan()); [Benchmark] public void HwIntrinsics() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); SimdUtils.HwIntrinsics.ByteToNormalizedFloat(sBytes, dFloats); } @@ -42,8 +33,8 @@ public class ToVector4_Rgba32 : ToVector4 // [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_2Loops() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dFloats.Length / (uint)Vector.Count; @@ -67,14 +58,14 @@ public class ToVector4_Rgba32 : ToVector4 } n = (uint)(dFloats.Length / Vector.Count); - var scale = new Vector(1f / 255f); + Vector scale = new(1f / 255f); for (nuint i = 0; i < n; i++) { ref Vector dRef = ref Unsafe.Add(ref destBase, i); - var du = Vector.AsVectorInt32(dRef); - var v = Vector.ConvertToSingle(du); + Vector du = Vector.AsVectorInt32(dRef); + Vector v = Vector.ConvertToSingle(du); v *= scale; dRef = v; @@ -84,14 +75,14 @@ public class ToVector4_Rgba32 : ToVector4 // [Benchmark] public void ExtendedIntrinsics_BulkConvertByteToNormalizedFloat_ConvertInSameLoop() { - Span sBytes = MemoryMarshal.Cast(this.source.GetSpan()); - Span dFloats = MemoryMarshal.Cast(this.destination.GetSpan()); + Span sBytes = MemoryMarshal.Cast(this.Source.GetSpan()); + Span dFloats = MemoryMarshal.Cast(this.Destination.GetSpan()); nuint n = (uint)dFloats.Length / (uint)Vector.Count; ref Vector sourceBase = ref Unsafe.As>(ref MemoryMarshal.GetReference((ReadOnlySpan)sBytes)); ref Vector destBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(dFloats)); - var scale = new Vector(1f / 255f); + Vector scale = new(1f / 255f); for (nuint i = 0; i < n; i++) { @@ -117,8 +108,8 @@ public class ToVector4_Rgba32 : ToVector4 [MethodImpl(MethodImplOptions.AggressiveInlining)] private static Vector ConvertToNormalizedSingle(Vector u, Vector scale) { - var vi = Vector.AsVectorInt32(u); - var v = Vector.ConvertToSingle(vi); + Vector vi = Vector.AsVectorInt32(u); + Vector v = Vector.ConvertToSingle(vi); v *= scale; return v; } @@ -151,4 +142,30 @@ public class ToVector4_Rgba32 : ToVector4 PixelOperations_Base | Core | 2048 | 6,752.68 ns | 272.820 ns | 15.4148 ns | 1.67 | 0.02 | - | 24 B | PixelOperations_Specialized | Core | 2048 | 1,126.13 ns | 79.192 ns | 4.4745 ns |!! 0.28 | 0.00 | - | 0 B | <--- ExtendedIntrinsics rock! */ + + /* + BenchmarkDotNet v0.13.10, Windows 11 (10.0.22631.3085/23H2/2023Update/SunValley3) + 11th Gen Intel Core i7-11370H 3.30GHz, 1 CPU, 8 logical and 4 physical cores + .NET SDK 8.0.200-preview.23624.5 + [Host] : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + Job-DFEQJT : .NET 8.0.1 (8.0.123.58001), X64 RyuJIT AVX2 + + Runtime=.NET 8.0 Arguments=/p:DebugType=portable IterationCount=3 + LaunchCount=1 WarmupCount=3 + + | Method | Count | Mean | Error | StdDev | Allocated | + |---------------------------- |------ |------------:|-----------:|----------:|----------:| + | FallbackIntrinsics128 | 64 | 139.66 ns | 27.429 ns | 1.503 ns | - | + | PixelOperations_Base | 64 | 124.65 ns | 29.653 ns | 1.625 ns | - | + | HwIntrinsics | 64 | 18.16 ns | 4.731 ns | 0.259 ns | - | + | PixelOperations_Specialized | 64 | 27.94 ns | 15.220 ns | 0.834 ns | - | + | FallbackIntrinsics128 | 256 | 525.07 ns | 34.397 ns | 1.885 ns | - | + | PixelOperations_Base | 256 | 464.17 ns | 46.897 ns | 2.571 ns | - | + | HwIntrinsics | 256 | 43.88 ns | 4.525 ns | 0.248 ns | - | + | PixelOperations_Specialized | 256 | 55.57 ns | 14.587 ns | 0.800 ns | - | + | FallbackIntrinsics128 | 2048 | 4,148.44 ns | 476.583 ns | 26.123 ns | - | + | PixelOperations_Base | 2048 | 3,608.42 ns | 66.293 ns | 3.634 ns | - | + | HwIntrinsics | 2048 | 361.42 ns | 35.576 ns | 1.950 ns | - | + | PixelOperations_Specialized | 2048 | 374.82 ns | 33.371 ns | 1.829 ns | - | + */ } diff --git a/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md b/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md index 6cb48eb48c..98f472241f 100644 --- a/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md +++ b/tests/ImageSharp.Benchmarks/LoadResizeSave/README.md @@ -1,4 +1,4 @@ -The benchmarks have been adapted from the +The benchmarks have been adapted from the [PhotoSauce's MemoryStress project](https://github.com/saucecontrol/core-imaging-playground/tree/beeees/MemoryStress). ### Setup diff --git a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs index e9e4550b04..36b3012640 100644 --- a/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs +++ b/tests/ImageSharp.Tests/Common/SimdUtilsTests.cs @@ -3,6 +3,7 @@ using System.Numerics; using System.Runtime.CompilerServices; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.Tests.TestUtilities; @@ -117,16 +118,10 @@ public partial class SimdUtilsTests public static readonly TheoryData ArbitraryArraySizes = new() { 0, 1, 2, 3, 4, 7, 8, 9, 15, 16, 17, 63, 64, 255, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520 }; [Theory] - [MemberData(nameof(ArraySizesDivisibleBy4))] - public void FallbackIntrinsics128_BulkConvertByteToNormalizedFloat(int count) => TestImpl_BulkConvertByteToNormalizedFloat( - count, - (s, d) => SimdUtils.FallbackIntrinsics128.ByteToNormalizedFloat(s.Span, d.Span)); - - [Theory] - [MemberData(nameof(ArraySizesDivisibleBy32))] + [MemberData(nameof(ArraySizesDivisibleBy64))] public void HwIntrinsics_BulkConvertByteToNormalizedFloat(int count) { - if (!Sse2.IsSupported) + if (!Sse2.IsSupported && !AdvSimd.IsSupported) { return; } @@ -138,7 +133,7 @@ public partial class SimdUtilsTests FeatureTestRunner.RunWithHwIntrinsicsFeature( RunTest, count, - HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE41); + HwIntrinsics.AllowAll | HwIntrinsics.DisableAVX512F | HwIntrinsics.DisableAVX2 | HwIntrinsics.DisableSSE41); } [Theory] @@ -160,32 +155,11 @@ public partial class SimdUtilsTests Assert.Equal(expected, result, new ApproximateFloatComparer(1e-5f)); } - [Theory] - [InlineData(1234)] - public void ExtendedIntrinsics_ConvertToSingle(short scale) - { - int n = Vector.Count; - short[] sData = new Random(scale).GenerateRandomInt16Array(2 * n, (short)-scale, scale); - float[] fData = sData.Select(u => (float)u).ToArray(); - - Vector source = new(sData); - - Vector expected1 = new(fData, 0); - Vector expected2 = new(fData, n); - - // Act: - SimdUtils.ExtendedIntrinsics.ConvertToSingle(source, out Vector actual1, out Vector actual2); - - // Assert: - Assert.Equal(expected1, actual1); - Assert.Equal(expected2, actual2); - } - [Theory] [MemberData(nameof(ArraySizesDivisibleBy64))] public void HwIntrinsics_BulkConvertNormalizedFloatToByteClampOverflows(int count) { - if (!Sse2.IsSupported) + if (!Sse2.IsSupported && !AdvSimd.IsSupported) { return; } From 0ec839fb931f3d1096c91c397857c31bf888b354 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 6 Feb 2024 17:34:13 +1000 Subject: [PATCH 145/219] Update SimdUtils.HwIntrinsics.cs --- src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 6f0b4b4e3c..6e45f1619c 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -761,10 +761,13 @@ internal static partial class SimdUtils { DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if (Avx2.IsSupported || Sse2.IsSupported) + if ((Vector512.IsHardwareAccelerated && Avx512F.IsSupported) || + Avx2.IsSupported || + Sse2.IsSupported || + AdvSimd.IsSupported) { int remainder; - if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) + if (Avx512F.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector512.Count); } @@ -877,7 +880,6 @@ internal static partial class SimdUtils ref Vector128 destinationBase = ref Unsafe.As>(ref MemoryMarshal.GetReference(destination)); Vector128 scale = Vector128.Create(1 / (float)byte.MaxValue); - Vector128 zero = Vector128.Zero; for (nuint i = 0; i < n; i++) { From c10863fee66d11cd4d9d0b030c4f7235dc3c1b1b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Tue, 6 Feb 2024 15:33:11 +0100 Subject: [PATCH 146/219] Replace Memory with string --- .../Formats/Jpeg/JpegDecoderCore.cs | 5 ++--- .../Formats/Jpeg/JpegEncoderCore.cs | 22 +++++++++---------- src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 4 ++-- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 2 +- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 10 ++++----- .../Formats/Jpg/JpegMetadataTests.cs | 10 ++++----- 6 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index d6b40fa7f7..5f3fa33fa6 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -524,13 +524,12 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) { Span temp = new byte[markerContentByteSize]; - char[] chars = new char[markerContentByteSize]; JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); stream.Read(temp); - Encoding.ASCII.GetChars(temp, chars); + string comment = Encoding.ASCII.GetString(temp); - metadata.Comments.Add(chars); + metadata.Comments.Add(comment); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 4dc9202070..8658f6b25f 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -186,23 +186,23 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals for (int i = 0; i < metadata.Comments.Count; i++) { - Memory chars = metadata.Comments[i]; + string comment = metadata.Comments[i]; - if (chars.Length > maxCommentLength) + if (comment.Length > maxCommentLength) { - Memory splitComment = chars.Slice(maxCommentLength, chars.Length - maxCommentLength); + string splitComment = comment.Substring(maxCommentLength, comment.Length - maxCommentLength); metadata.Comments.Insert(i + 1, splitComment); // We don't want to keep the extra bytes - chars = chars.Slice(0, maxCommentLength); + comment = comment.Substring(0, maxCommentLength); } - int commentLength = chars.Length + 4; + int commentLength = comment.Length + 4; - Span comment = new byte[commentLength]; - Span markers = comment.Slice(0, 2); - Span payloadSize = comment.Slice(2, 2); - Span payload = comment.Slice(4, chars.Length); + Span commentSpan = new byte[commentLength]; + Span markers = commentSpan.Slice(0, 2); + Span payloadSize = commentSpan.Slice(2, 2); + Span payload = commentSpan.Slice(4, comment.Length); // Beginning of comment ff fe markers[0] = JpegConstants.Markers.XFF; @@ -213,9 +213,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals payloadSize[0] = (byte)((comWithoutMarker >> 8) & 0xFF); payloadSize[1] = (byte)(comWithoutMarker & 0xFF); - Encoding.ASCII.GetBytes(chars.Span, payload); + Encoding.ASCII.GetBytes(comment, payload); - this.outputStream.Write(comment, 0, comment.Length); + this.outputStream.Write(commentSpan, 0, commentSpan.Length); } } diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index bf758dfd09..5b96fdf967 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -15,7 +15,7 @@ public class JpegMetadata : IDeepCloneable /// public JpegMetadata() { - this.Comments = new List>(); + this.Comments = new List(); } /// @@ -106,7 +106,7 @@ public class JpegMetadata : IDeepCloneable /// /// Gets the comments. /// - public IList> Comments { get; } + public IList Comments { get; } /// public IDeepCloneable DeepClone() => new JpegMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 369e71abfc..222d1fb8cf 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -435,7 +435,7 @@ public partial class JpegDecoderTests JpegMetadata metadata = image.Metadata.GetJpegMetadata(); Assert.Equal(1, metadata.Comments.Count); - Assert.Equal(expectedComment.ToCharArray(), metadata.Comments.ElementAtOrDefault(0)); + Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0)); image.DebugSave(provider); image.CompareToOriginal(provider); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index 8cc64acea3..f33234e322 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -172,7 +172,7 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(1, actual.Comments.Count); - Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0).ToString()); + Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0)); } [Fact] @@ -184,8 +184,8 @@ public partial class JpegEncoderTests using var memStream = new MemoryStream(); // act - meta.Comments.Add("First comment".ToCharArray()); - meta.Comments.Add("Second Comment".ToCharArray()); + meta.Comments.Add("First comment"); + meta.Comments.Add("Second Comment"); input.Save(memStream, JpegEncoder); // assert @@ -194,8 +194,8 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(2, actual.Comments.Count); - Assert.Equal(meta.Comments.ElementAtOrDefault(0).ToString(), actual.Comments.ElementAtOrDefault(0).ToString()); - Assert.Equal(meta.Comments.ElementAtOrDefault(1).ToString(), actual.Comments.ElementAtOrDefault(1).ToString()); + Assert.Equal(meta.Comments.ElementAtOrDefault(0), actual.Comments.ElementAtOrDefault(0)); + Assert.Equal(meta.Comments.ElementAtOrDefault(1), actual.Comments.ElementAtOrDefault(1)); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 8b991228b4..64d7edd759 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -64,19 +64,19 @@ public class JpegMetadataTests { var meta = new JpegMetadata(); - Assert.True(Array.Empty>().SequenceEqual(meta.Comments)); + Assert.True(Array.Empty().SequenceEqual(meta.Comments)); } [Fact] public void Comment_OnlyComment() { string comment = "test comment"; - var expectedCollection = new Collection> { new(comment.ToCharArray()) }; + var expectedCollection = new Collection { comment }; var meta = new JpegMetadata(); - meta.Comments?.Add(comment.ToCharArray()); + meta.Comments.Add(comment); - Assert.Equal(1, meta.Comments?.Count); - Assert.True(expectedCollection.FirstOrDefault().ToString() == meta.Comments?.FirstOrDefault().ToString()); + Assert.Equal(1, meta.Comments.Count); + Assert.True(expectedCollection.FirstOrDefault() == meta.Comments.FirstOrDefault()); } } From d2251287ceaeb0c827d62b29a651775fd2daaa83 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Tue, 6 Feb 2024 16:16:35 +0100 Subject: [PATCH 147/219] Introduce JpegComData.cs --- src/ImageSharp/Formats/Jpeg/JpegComData.cs | 32 +++++++++++++++++++ .../Formats/Jpeg/JpegDecoderCore.cs | 2 +- .../Formats/Jpeg/JpegEncoderCore.cs | 4 +-- src/ImageSharp/Formats/Jpeg/JpegMetadata.cs | 4 +-- .../Formats/Jpg/JpegDecoderTests.Metadata.cs | 2 +- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 10 +++--- .../Formats/Jpg/JpegMetadataTests.cs | 6 ++-- 7 files changed, 46 insertions(+), 14 deletions(-) create mode 100644 src/ImageSharp/Formats/Jpeg/JpegComData.cs diff --git a/src/ImageSharp/Formats/Jpeg/JpegComData.cs b/src/ImageSharp/Formats/Jpeg/JpegComData.cs new file mode 100644 index 0000000000..26ade0217f --- /dev/null +++ b/src/ImageSharp/Formats/Jpeg/JpegComData.cs @@ -0,0 +1,32 @@ +// Copyright (c) Six Labors. +// Licensed under the Six Labors Split License. + +namespace SixLabors.ImageSharp.Formats.Jpeg; + +/// +/// Contains JPEG comment +/// +public readonly struct JpegComData +{ + /// + /// Converts string to + /// + /// The comment string. + /// The + public static JpegComData FromString(string value) => new(value.AsMemory()); + + /// + /// Initializes a new instance of the struct. + /// + /// The comment ReadOnlyMemory of chars. + public JpegComData(ReadOnlyMemory value) + => this.Value = value; + + public ReadOnlyMemory Value { get; } + + /// + /// Converts Value to string + /// + /// The comment string. + public override string ToString() => this.Value.ToString(); +} diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index 5f3fa33fa6..e43c20a7d9 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -529,7 +529,7 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals stream.Read(temp); string comment = Encoding.ASCII.GetString(temp); - metadata.Comments.Add(comment); + metadata.Comments.Add(JpegComData.FromString(comment)); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 8658f6b25f..a55435c532 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -186,12 +186,12 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals for (int i = 0; i < metadata.Comments.Count; i++) { - string comment = metadata.Comments[i]; + string comment = metadata.Comments[i].ToString(); if (comment.Length > maxCommentLength) { string splitComment = comment.Substring(maxCommentLength, comment.Length - maxCommentLength); - metadata.Comments.Insert(i + 1, splitComment); + metadata.Comments.Insert(i + 1, JpegComData.FromString(splitComment)); // We don't want to keep the extra bytes comment = comment.Substring(0, maxCommentLength); diff --git a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs index 5b96fdf967..fe1324a862 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegMetadata.cs @@ -15,7 +15,7 @@ public class JpegMetadata : IDeepCloneable /// public JpegMetadata() { - this.Comments = new List(); + this.Comments = new List(); } /// @@ -106,7 +106,7 @@ public class JpegMetadata : IDeepCloneable /// /// Gets the comments. /// - public IList Comments { get; } + public IList Comments { get; } /// public IDeepCloneable DeepClone() => new JpegMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs index 222d1fb8cf..cbb2befcd4 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.Metadata.cs @@ -435,7 +435,7 @@ public partial class JpegDecoderTests JpegMetadata metadata = image.Metadata.GetJpegMetadata(); Assert.Equal(1, metadata.Comments.Count); - Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0)); + Assert.Equal(expectedComment, metadata.Comments.ElementAtOrDefault(0).ToString()); image.DebugSave(provider); image.CompareToOriginal(provider); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index f33234e322..e49afedbb5 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -172,7 +172,7 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(1, actual.Comments.Count); - Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0)); + Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0).ToString()); } [Fact] @@ -184,8 +184,8 @@ public partial class JpegEncoderTests using var memStream = new MemoryStream(); // act - meta.Comments.Add("First comment"); - meta.Comments.Add("Second Comment"); + meta.Comments.Add(JpegComData.FromString("First comment")); + meta.Comments.Add(JpegComData.FromString("Second Comment")); input.Save(memStream, JpegEncoder); // assert @@ -194,8 +194,8 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(2, actual.Comments.Count); - Assert.Equal(meta.Comments.ElementAtOrDefault(0), actual.Comments.ElementAtOrDefault(0)); - Assert.Equal(meta.Comments.ElementAtOrDefault(1), actual.Comments.ElementAtOrDefault(1)); + Assert.Equal(meta.Comments.ElementAtOrDefault(0).ToString(), actual.Comments.ElementAtOrDefault(0).ToString()); + Assert.Equal(meta.Comments.ElementAtOrDefault(1).ToString(), actual.Comments.ElementAtOrDefault(1).ToString()); } [Theory] diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs index 64d7edd759..e07c42f898 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegMetadataTests.cs @@ -64,7 +64,7 @@ public class JpegMetadataTests { var meta = new JpegMetadata(); - Assert.True(Array.Empty().SequenceEqual(meta.Comments)); + Assert.True(Array.Empty().SequenceEqual(meta.Comments)); } [Fact] @@ -74,9 +74,9 @@ public class JpegMetadataTests var expectedCollection = new Collection { comment }; var meta = new JpegMetadata(); - meta.Comments.Add(comment); + meta.Comments.Add(JpegComData.FromString(comment)); Assert.Equal(1, meta.Comments.Count); - Assert.True(expectedCollection.FirstOrDefault() == meta.Comments.FirstOrDefault()); + Assert.True(expectedCollection.FirstOrDefault() == meta.Comments.FirstOrDefault().ToString()); } } From 4e494d427f667c94fb59bcad972ac2f45410e826 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 14 Feb 2024 11:55:07 +1000 Subject: [PATCH 148/219] Simplify checks --- .../Common/Helpers/SimdUtils.Convert.cs | 7 ++--- .../Common/Helpers/SimdUtils.HwIntrinsics.cs | 26 +++++++------------ 2 files changed, 14 insertions(+), 19 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs index 1b5a418dea..5318ad0497 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.Convert.cs @@ -57,7 +57,7 @@ internal static partial class SimdUtils for (int i = 0; i < source.Length; i++) { - Unsafe.Add(ref dBase, i) = Unsafe.Add(ref sBase, i) / 255f; + Unsafe.Add(ref dBase, (uint)i) = Unsafe.Add(ref sBase, (uint)i) / 255f; } } @@ -66,12 +66,13 @@ internal static partial class SimdUtils { ref float sBase = ref MemoryMarshal.GetReference(source); ref byte dBase = ref MemoryMarshal.GetReference(destination); + for (int i = 0; i < source.Length; i++) { - Unsafe.Add(ref dBase, i) = ConvertToByte(Unsafe.Add(ref sBase, i)); + Unsafe.Add(ref dBase, (uint)i) = ConvertToByte(Unsafe.Add(ref sBase, (uint)i)); } } [MethodImpl(MethodImplOptions.AggressiveInlining)] - private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255F) + 0.5F, 0, 255F); + private static byte ConvertToByte(float f) => (byte)Numerics.Clamp((f * 255f) + 0.5f, 0, 255f); } diff --git a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs index 6e45f1619c..17ccb396d6 100644 --- a/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs +++ b/src/ImageSharp/Common/Helpers/SimdUtils.HwIntrinsics.cs @@ -761,13 +761,10 @@ internal static partial class SimdUtils { DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if ((Vector512.IsHardwareAccelerated && Avx512F.IsSupported) || - Avx2.IsSupported || - Sse2.IsSupported || - AdvSimd.IsSupported) + if (Vector128.IsHardwareAccelerated) { int remainder; - if (Avx512F.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector512.Count); } @@ -805,7 +802,7 @@ internal static partial class SimdUtils ReadOnlySpan source, Span destination) { - if (Avx512F.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512F.IsSupported) { DebugVerifySpanInput(source, destination, Vector512.Count); @@ -870,7 +867,7 @@ internal static partial class SimdUtils Unsafe.Add(ref d, 3) = f3; } } - else if (Sse2.IsSupported || AdvSimd.IsSupported) + else if (Vector128.IsHardwareAccelerated) { DebugVerifySpanInput(source, destination, Vector128.Count); @@ -897,7 +894,7 @@ internal static partial class SimdUtils } else { - // Sse2, AdvSimd + // Sse2, AdvSimd, etc Vector128 b = Vector128.LoadUnsafe(ref sourceBase, si); (Vector128 s0, Vector128 s1) = Vector128.Widen(b); (i0, i1) = Vector128.Widen(s0.AsInt16()); @@ -931,13 +928,11 @@ internal static partial class SimdUtils { DebugGuard.IsTrue(source.Length == destination.Length, nameof(source), "Input spans must be of same length!"); - if ((Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) || - (Vector256.IsHardwareAccelerated && Avx2.IsSupported) || - (Vector128.IsHardwareAccelerated && (Sse2.IsSupported || AdvSimd.IsSupported))) + if (Sse2.IsSupported || AdvSimd.IsSupported) { int remainder; - if (Avx512BW.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) { remainder = Numerics.ModuloP2(source.Length, Vector512.Count); } @@ -977,7 +972,7 @@ internal static partial class SimdUtils ReadOnlySpan source, Span destination) { - if (Avx512BW.IsSupported) + if (Vector512.IsHardwareAccelerated && Avx512BW.IsSupported) { DebugVerifySpanInput(source, destination, Vector512.Count); @@ -1011,8 +1006,7 @@ internal static partial class SimdUtils Unsafe.Add(ref destinationBase, i) = b; } } - else - if (Avx2.IsSupported) + else if (Avx2.IsSupported) { DebugVerifySpanInput(source, destination, Vector256.Count); @@ -1046,7 +1040,7 @@ internal static partial class SimdUtils Unsafe.Add(ref destinationBase, i) = b; } } - else + else if (Sse2.IsSupported || AdvSimd.IsSupported) { // Sse, AdvSimd DebugVerifySpanInput(source, destination, Vector128.Count); From d865ab96f27d07435355d858fa67fb6fbad028ae Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 23 Feb 2024 13:00:47 +0000 Subject: [PATCH 149/219] Bump NuGet/setup-nuget from 1 to 2 Bumps [NuGet/setup-nuget](https://github.com/nuget/setup-nuget) from 1 to 2. - [Release notes](https://github.com/nuget/setup-nuget/releases) - [Commits](https://github.com/nuget/setup-nuget/compare/v1...v2) --- updated-dependencies: - dependency-name: NuGet/setup-nuget dependency-type: direct:production update-type: version-update:semver-major ... Signed-off-by: dependabot[bot] --- .github/workflows/build-and-test.yml | 4 ++-- .github/workflows/code-coverage.yml | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 57488a1d0a..52a52c472b 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -77,7 +77,7 @@ jobs: run: git lfs pull - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache uses: actions/cache@v4 @@ -159,7 +159,7 @@ jobs: submodules: recursive - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache uses: actions/cache@v4 diff --git a/.github/workflows/code-coverage.yml b/.github/workflows/code-coverage.yml index 58e19631f5..d531e68601 100644 --- a/.github/workflows/code-coverage.yml +++ b/.github/workflows/code-coverage.yml @@ -44,7 +44,7 @@ jobs: run: git lfs pull - name: NuGet Install - uses: NuGet/setup-nuget@v1 + uses: NuGet/setup-nuget@v2 - name: NuGet Setup Cache uses: actions/cache@v4 From a940a55f5374e0baacb4da23dc85e7dd91807109 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 23 Feb 2024 23:07:34 +1000 Subject: [PATCH 150/219] Make DrawImage processor more robust to bad input. --- .../Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs index 0d81270b16..d5499d5865 100644 --- a/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs +++ b/src/ImageSharp/Processing/Processors/Drawing/DrawImageProcessor{TPixelBg,TPixelFg}.cs @@ -98,9 +98,10 @@ internal class DrawImageProcessor : ImageProcessor top = 0; } - // clamp the height/width to the availible space left to prevent overflowing + // Clamp the height/width to the available space left to prevent overflowing foregroundRectangle.Width = Math.Min(source.Width - left, foregroundRectangle.Width); foregroundRectangle.Height = Math.Min(source.Height - top, foregroundRectangle.Height); + foregroundRectangle = Rectangle.Intersect(foregroundRectangle, this.ForegroundImage.Bounds); int width = foregroundRectangle.Width; int height = foregroundRectangle.Height; @@ -111,7 +112,6 @@ internal class DrawImageProcessor : ImageProcessor } // Sanitize the dimensions so that we don't try and sample outside the image. - foregroundRectangle = Rectangle.Intersect(foregroundRectangle, this.ForegroundImage.Bounds); Rectangle backgroundRectangle = Rectangle.Intersect(new(left, top, width, height), this.SourceRectangle); Configuration configuration = this.Configuration; From b4049ce517ddd94fdbac398633f895957defe157 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 24 Feb 2024 00:12:15 +1000 Subject: [PATCH 151/219] Don't skip data read on animation and frame control chunks --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 9 +++++++-- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 8 ++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Png/issues/Issue_2666.png | 3 +++ 4 files changed, 19 insertions(+), 2 deletions(-) create mode 100644 tests/Images/Input/Png/issues/Issue_2666.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 95154d68d3..179bf38ba8 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1871,8 +1871,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals PngChunkType type = this.ReadChunkType(buffer); // If we're reading color metadata only we're only interested in the IHDR and tRNS chunks. - // We can skip all other chunk data in the stream for better performance. - if (this.colorMetadataOnly && type != PngChunkType.Header && type != PngChunkType.Transparency && type != PngChunkType.Palette) + // We can skip most other chunk data in the stream for better performance. + if (this.colorMetadataOnly && + type != PngChunkType.Header && + type != PngChunkType.Transparency && + type != PngChunkType.Palette && + type != PngChunkType.AnimationControl && + type != PngChunkType.FrameControl) { chunk = new PngChunk(length, type); return true; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index bc277bf485..743d1f797c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.IO; using System.Runtime.Intrinsics.X86; using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; @@ -665,4 +666,11 @@ public partial class PngDecoderTests Assert.True(eofHitCounter.EofHitCount <= 3); Assert.Equal(new Size(200, 120), eofHitCounter.Image.Size); } + + [Fact] + public void Decode_Issue2666() + { + string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Png.Issue2666)); + using Image image = Image.Load(path); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 8aa95d3496..82db313585 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -73,6 +73,7 @@ public static class TestImages public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png"; public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; + public const string Issue2666 = "Png/Issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; diff --git a/tests/Images/Input/Png/issues/Issue_2666.png b/tests/Images/Input/Png/issues/Issue_2666.png new file mode 100644 index 0000000000..b918fd4744 --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2666.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ed7665cdfd5fad00c5995040350a254b96af6c0c95ab13975f2291e9d3fce0f3 +size 8244837 From 83ecbdb19fb180266a154896ccb9949f3bdd8c5d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 10:27:03 +1000 Subject: [PATCH 152/219] Fix path --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 1 - tests/ImageSharp.Tests/TestImages.cs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 743d1f797c..b9f6075fb8 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -1,7 +1,6 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. -using System.IO; using System.Runtime.Intrinsics.X86; using Microsoft.DotNet.RemoteExecutor; using SixLabors.ImageSharp.Formats; diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 82db313585..4e33bbd8ad 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -73,7 +73,7 @@ public static class TestImages public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png"; public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; - public const string Issue2666 = "Png/Issues/Issue_2666.png"; + public const string Issue2666 = "Png/issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html public const string Filter0 = "Png/filter0.png"; From 3c65383dec1c0291824596a485c6840b8bf38e1a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 11:56:46 +1000 Subject: [PATCH 153/219] Prevent underflow --- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 10 ++++------ .../ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs | 11 +++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Webp/issues/Issue2670.webp | 3 +++ 4 files changed, 19 insertions(+), 6 deletions(-) create mode 100644 tests/Images/Input/Webp/issues/Issue2670.webp diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 63e6541354..125ed0acd7 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossless; @@ -311,18 +312,15 @@ internal class AlphaDecoder : IDisposable private static void HorizontalUnfilter(Span prev, Span input, Span dst, int width) { - if (Sse2.IsSupported) + // TODO: Investigate AdvSim support for this method. + if (Sse2.IsSupported && width >= 9) { dst[0] = (byte)(input[0] + (prev.IsEmpty ? 0 : prev[0])); - if (width <= 1) - { - return; - } - nuint i; Vector128 last = Vector128.Zero.WithElement(0, dst[0]); ref byte srcRef = ref MemoryMarshal.GetReference(input); ref byte dstRef = ref MemoryMarshal.GetReference(dst); + for (i = 1; i <= (uint)width - 8; i += 8) { Vector128 a0 = Vector128.Create(Unsafe.As(ref Unsafe.Add(ref srcRef, i)), 0); diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index c38b13075a..0dda304b64 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -439,6 +439,17 @@ public class WebpDecoderTests image.CompareToOriginal(provider, ReferenceDecoder); } + // https://github.com/SixLabors/ImageSharp/issues/2670 + [Theory] + [WithFile(Lossy.Issue2670, PixelTypes.Rgba32)] + public void WebpDecoder_CanDecode_Issue2670(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(WebpDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider, ReferenceDecoder); + } + [Theory] [WithFile(Lossless.LossLessCorruptImage3, PixelTypes.Rgba32)] public void WebpDecoder_ThrowImageFormatException_OnInvalidImages(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4e33bbd8ad..b2085c6836 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -804,6 +804,7 @@ public static class TestImages public const string Issue1594 = "Webp/issues/Issue1594.webp"; public const string Issue2243 = "Webp/issues/Issue2243.webp"; public const string Issue2257 = "Webp/issues/Issue2257.webp"; + public const string Issue2670 = "Webp/issues/Issue2670.webp"; } } diff --git a/tests/Images/Input/Webp/issues/Issue2670.webp b/tests/Images/Input/Webp/issues/Issue2670.webp new file mode 100644 index 0000000000..4dd1248986 --- /dev/null +++ b/tests/Images/Input/Webp/issues/Issue2670.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23ad5eb449f693af68e51dd108a6b9847a8eb48b82ca5b848395a54c2e0be08f +size 152 From 15619ecd88bc67b6bf4a002094ba241836f8f10a Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 12:01:11 +1000 Subject: [PATCH 154/219] Fix file name --- tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 2 +- .../Images/Input/Webp/issues/{Issue2670.webp => Issue2676.webp} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/Images/Input/Webp/issues/{Issue2670.webp => Issue2676.webp} (100%) diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index 0dda304b64..b0b7c294ab 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -441,7 +441,7 @@ public class WebpDecoderTests // https://github.com/SixLabors/ImageSharp/issues/2670 [Theory] - [WithFile(Lossy.Issue2670, PixelTypes.Rgba32)] + [WithFile(Lossy.Issue2676, PixelTypes.Rgba32)] public void WebpDecoder_CanDecode_Issue2670(TestImageProvider provider) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index b2085c6836..1eba38e4a3 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -804,7 +804,7 @@ public static class TestImages public const string Issue1594 = "Webp/issues/Issue1594.webp"; public const string Issue2243 = "Webp/issues/Issue2243.webp"; public const string Issue2257 = "Webp/issues/Issue2257.webp"; - public const string Issue2670 = "Webp/issues/Issue2670.webp"; + public const string Issue2676 = "Webp/issues/Issue2676.webp"; } } diff --git a/tests/Images/Input/Webp/issues/Issue2670.webp b/tests/Images/Input/Webp/issues/Issue2676.webp similarity index 100% rename from tests/Images/Input/Webp/issues/Issue2670.webp rename to tests/Images/Input/Webp/issues/Issue2676.webp From 12d05b77cd3cbf1ceab13f8c60c62f8600060fbc Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 12:04:03 +1000 Subject: [PATCH 155/219] Revert "Fix file name" This reverts commit 15619ecd88bc67b6bf4a002094ba241836f8f10a. --- tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs | 2 +- tests/ImageSharp.Tests/TestImages.cs | 2 +- .../Images/Input/Webp/issues/{Issue2676.webp => Issue2670.webp} | 0 3 files changed, 2 insertions(+), 2 deletions(-) rename tests/Images/Input/Webp/issues/{Issue2676.webp => Issue2670.webp} (100%) diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index b0b7c294ab..0dda304b64 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -441,7 +441,7 @@ public class WebpDecoderTests // https://github.com/SixLabors/ImageSharp/issues/2670 [Theory] - [WithFile(Lossy.Issue2676, PixelTypes.Rgba32)] + [WithFile(Lossy.Issue2670, PixelTypes.Rgba32)] public void WebpDecoder_CanDecode_Issue2670(TestImageProvider provider) where TPixel : unmanaged, IPixel { diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1eba38e4a3..b2085c6836 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -804,7 +804,7 @@ public static class TestImages public const string Issue1594 = "Webp/issues/Issue1594.webp"; public const string Issue2243 = "Webp/issues/Issue2243.webp"; public const string Issue2257 = "Webp/issues/Issue2257.webp"; - public const string Issue2676 = "Webp/issues/Issue2676.webp"; + public const string Issue2670 = "Webp/issues/Issue2670.webp"; } } diff --git a/tests/Images/Input/Webp/issues/Issue2676.webp b/tests/Images/Input/Webp/issues/Issue2670.webp similarity index 100% rename from tests/Images/Input/Webp/issues/Issue2676.webp rename to tests/Images/Input/Webp/issues/Issue2670.webp From 223f6474c2035171de7fa4e43a8cd088f172e4a1 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 12:04:37 +1000 Subject: [PATCH 156/219] Update AlphaDecoder.cs --- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 125ed0acd7..7033bf167c 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -6,7 +6,6 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; -using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossless; From 2a548818ac3c7a5e328c72757f5464007579d851 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 16:35:28 +1000 Subject: [PATCH 157/219] Use a smarter approach to determine the transparent index --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 20 ++++++++++++++++++- .../Formats/Png/PngEncoderTests.cs | 17 ++++++++++++++++ tests/ImageSharp.Tests/TestImages.cs | 3 +++ ...antized_Encode_Alpha_Rgba32_issue_2668.png | 3 +++ tests/Images/Input/Png/issues/Issue_2668.png | 3 +++ 5 files changed, 45 insertions(+), 1 deletion(-) create mode 100644 tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png create mode 100644 tests/Images/Input/Png/issues/Issue_2668.png diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ddef1c9cd9..ea94270f2f 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -3,6 +3,7 @@ using System.Buffers; using System.Buffers.Binary; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; @@ -1527,7 +1528,24 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { // We can use the color data from the decoded metadata here. // We avoid dithering by default to preserve the original colors. - this.derivedTransparencyIndex = metadata.ColorTable.Value.Span.IndexOf(Color.Transparent); + ReadOnlySpan palette = metadata.ColorTable.Value.Span; + + // Certain operations perform alpha premultiplication, which can cause the color to change so we + // must search for the transparency index in the palette. + // Transparent pixels are much more likely to be found at the end of a palette. + int index = -1; + for (int i = palette.Length - 1; i >= 0; i--) + { + Vector4 instance = palette[i].ToScaledVector4(); + if (instance.W == 0f) + { + index = i; + break; + } + } + + this.derivedTransparencyIndex = index; + this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }, this.derivedTransparencyIndex); } else diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index e70854b082..950f1d2e3a 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -678,6 +679,22 @@ public partial class PngEncoderTests encoded.CompareToReferenceOutput(ImageComparer.Exact, provider); } + // https://github.com/SixLabors/ImageSharp/issues/2469 + [Theory] + [WithFile(TestImages.Png.Issue2668, PixelTypes.Rgba32)] + public void Issue2668_Quantized_Encode_Alpha(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + image.Mutate(x => x.Resize(100, 100)); + + PngEncoder encoder = new() { BitDepth = PngBitDepth.Bit8, ColorType = PngColorType.Palette }; + + string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder); + using Image encoded = Image.Load(actualOutputFile); + encoded.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 4e33bbd8ad..a6532a0905 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -151,6 +151,9 @@ public static class TestImages // Issue 2447: https://github.com/SixLabors/ImageSharp/issues/2447 public const string Issue2447 = "Png/issues/issue_2447.png"; + // Issue 2668: https://github.com/SixLabors/ImageSharp/issues/2668 + public const string Issue2668 = "Png/issues/issue_2668.png"; + public static class Bad { public const string MissingDataChunk = "Png/xdtn0g01.png"; diff --git a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png new file mode 100644 index 0000000000..7af5391f70 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f934af128b85b9e8f557d71ac8b1f1473a0922d0754fc0c4ece0d0e3d8d94c39 +size 7702 diff --git a/tests/Images/Input/Png/issues/Issue_2668.png b/tests/Images/Input/Png/issues/Issue_2668.png new file mode 100644 index 0000000000..2ca8c46171 --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2668.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8e5b2b933fd8fefd161f1d22970cb60247fd2d93b6c07b8b9ee1fdbc2241a3c +size 390225 From ed2cd3184ff9478f265fbb4ec40482d44e6d971d Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 20:38:29 +1000 Subject: [PATCH 158/219] Fix casing --- tests/ImageSharp.Tests/TestImages.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index a6532a0905..3d9da1072a 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -152,7 +152,7 @@ public static class TestImages public const string Issue2447 = "Png/issues/issue_2447.png"; // Issue 2668: https://github.com/SixLabors/ImageSharp/issues/2668 - public const string Issue2668 = "Png/issues/issue_2668.png"; + public const string Issue2668 = "Png/issues/Issue_2668.png"; public static class Bad { From f6d24ed15c94a5a7ca20bdcbb3b4a52c15564544 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 20:49:13 +1000 Subject: [PATCH 159/219] Update src/ImageSharp/Formats/Webp/AlphaDecoder.cs MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Günther Foidl --- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 7033bf167c..63571617fb 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -311,7 +311,7 @@ internal class AlphaDecoder : IDisposable private static void HorizontalUnfilter(Span prev, Span input, Span dst, int width) { - // TODO: Investigate AdvSim support for this method. + // TODO: Investigate AdvSimd support for this method. if (Sse2.IsSupported && width >= 9) { dst[0] = (byte)(input[0] + (prev.IsEmpty ? 0 : prev[0])); From 624277ba8803fc8b8062139c44cefe88118473a5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Mon, 26 Feb 2024 21:01:40 +1000 Subject: [PATCH 160/219] Update Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png --- ...png => Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename tests/Images/External/ReferenceOutput/PngEncoderTests/{Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png => Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png} (100%) diff --git a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png similarity index 100% rename from tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_issue_2668.png rename to tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png From f44b761f3b6731e2c20b56f10515962178ed958c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 27 Feb 2024 11:09:36 +1000 Subject: [PATCH 161/219] Add fixes 2668, 2676, and 2677 to main (#2678) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * Prevent underflow * Fix file name * Revert "Fix file name" This reverts commit 15619ecd88bc67b6bf4a002094ba241836f8f10a. * Update AlphaDecoder.cs * Use a smarter approach to determine the transparent index * Fix casing * Update src/ImageSharp/Formats/Webp/AlphaDecoder.cs Co-authored-by: Günther Foidl * Update Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png * Normalize Color API * Aggressive inlining --------- Co-authored-by: Günther Foidl --- src/ImageSharp/Color/Color.cs | 93 +++++++++---------- .../Formats/Gif/GifFrameMetadata.cs | 4 +- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 20 +++- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 9 +- .../Color/ColorTests.CastTo.cs | 2 +- .../Formats/Png/PngEncoderTests.cs | 17 ++++ .../Formats/WebP/WebpDecoderTests.cs | 11 +++ tests/ImageSharp.Tests/TestImages.cs | 4 + ...antized_Encode_Alpha_Rgba32_Issue_2668.png | 3 + tests/Images/Input/Png/issues/Issue_2668.png | 3 + tests/Images/Input/Webp/issues/Issue2670.webp | 3 + 11 files changed, 112 insertions(+), 57 deletions(-) create mode 100644 tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png create mode 100644 tests/Images/Input/Png/issues/Issue_2668.png create mode 100644 tests/Images/Input/Webp/issues/Issue2670.webp diff --git a/src/ImageSharp/Color/Color.cs b/src/ImageSharp/Color/Color.cs index 82ecab3909..8f54680ec4 100644 --- a/src/ImageSharp/Color/Color.cs +++ b/src/ImageSharp/Color/Color.cs @@ -25,7 +25,7 @@ public readonly partial struct Color : IEquatable /// Initializes a new instance of the struct. /// /// The containing the color information. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private Color(Vector4 vector) { this.data = Numerics.Clamp(vector, Vector4.Zero, Vector4.One); @@ -36,28 +36,13 @@ public readonly partial struct Color : IEquatable /// Initializes a new instance of the struct. /// /// The pixel containing color information. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] private Color(IPixel pixel) { this.boxedHighPrecisionPixel = pixel; this.data = default; } - /// - /// Converts a to . - /// - /// The . - /// The . - public static explicit operator Vector4(Color color) => color.ToScaledVector4(); - - /// - /// Converts an to . - /// - /// The . - /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static explicit operator Color(Vector4 source) => new(source); - /// /// Checks whether two structures are equal. /// @@ -67,7 +52,7 @@ public readonly partial struct Color : IEquatable /// True if the parameter is equal to the parameter; /// otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator ==(Color left, Color right) => left.Equals(right); /// @@ -79,36 +64,44 @@ public readonly partial struct Color : IEquatable /// True if the parameter is not equal to the parameter; /// otherwise, false. /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool operator !=(Color left, Color right) => !left.Equals(right); /// /// Creates a from the given . /// - /// The pixel to convert from. + /// The pixel to convert from. /// The pixel format. /// The . - [MethodImpl(InliningOptions.ShortMethod)] - public static Color FromPixel(TPixel pixel) + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Color FromPixel(TPixel source) where TPixel : unmanaged, IPixel { // Avoid boxing in case we can convert to Vector4 safely and efficiently PixelTypeInfo info = TPixel.GetPixelTypeInfo(); if (info.ComponentInfo.HasValue && info.ComponentInfo.Value.GetMaximumComponentPrecision() <= (int)PixelComponentBitDepth.Bit32) { - return new(pixel.ToScaledVector4()); + return new(source.ToScaledVector4()); } - return new(pixel); + return new(source); } + /// + /// Creates a from a generic scaled . + /// + /// The vector to load the pixel from. + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public static Color FromScaledVector(Vector4 source) => new(source); + /// /// Bulk converts a span of a specified type to a span of . /// /// The pixel type to convert to. /// The source pixel span. /// The destination color span. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void FromPixel(ReadOnlySpan source, Span destination) where TPixel : unmanaged, IPixel { @@ -120,7 +113,7 @@ public readonly partial struct Color : IEquatable { for (int i = 0; i < destination.Length; i++) { - destination[i] = new(source[i].ToScaledVector4()); + destination[i] = FromScaledVector(source[i].ToScaledVector4()); } } else @@ -143,7 +136,7 @@ public readonly partial struct Color : IEquatable /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static Color ParseHex(string hex) { Rgba32 rgba = Rgba32.ParseHex(hex); @@ -162,7 +155,7 @@ public readonly partial struct Color : IEquatable /// /// The . /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static bool TryParseHex(string hex, out Color result) { result = default; @@ -236,16 +229,16 @@ public readonly partial struct Color : IEquatable /// The color having it's alpha channel altered. public Color WithAlpha(float alpha) { - Vector4 v = (Vector4)this; + Vector4 v = this.ToScaledVector4(); v.W = alpha; - return new Color(v); + return FromScaledVector(v); } /// /// Gets the hexadecimal representation of the color instance in rrggbbaa form. /// /// A hexadecimal string representation of the value. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public string ToHex() { if (this.boxedHighPrecisionPixel is not null) @@ -263,8 +256,8 @@ public readonly partial struct Color : IEquatable /// Converts the color instance to a specified type. /// /// The pixel type to convert to. - /// The pixel value. - [MethodImpl(InliningOptions.ShortMethod)] + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] public TPixel ToPixel() where TPixel : unmanaged, IPixel { @@ -281,13 +274,30 @@ public readonly partial struct Color : IEquatable return TPixel.FromScaledVector4(this.boxedHighPrecisionPixel.ToScaledVector4()); } + /// + /// Expands the color into a generic ("scaled") representation + /// with values scaled and clamped between 0 and 1. + /// The vector components are typically expanded in least to greatest significance order. + /// + /// The . + [MethodImpl(MethodImplOptions.AggressiveInlining)] + public Vector4 ToScaledVector4() + { + if (this.boxedHighPrecisionPixel is null) + { + return this.data; + } + + return this.boxedHighPrecisionPixel.ToScaledVector4(); + } + /// /// Bulk converts a span of to a span of a specified type. /// /// The pixel type to convert to. /// The source color span. /// The destination pixel span. - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public static void ToPixel(ReadOnlySpan source, Span destination) where TPixel : unmanaged, IPixel { @@ -301,7 +311,7 @@ public readonly partial struct Color : IEquatable } /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public bool Equals(Color other) { if (this.boxedHighPrecisionPixel is null && other.boxedHighPrecisionPixel is null) @@ -316,7 +326,7 @@ public readonly partial struct Color : IEquatable public override bool Equals(object? obj) => obj is Color other && this.Equals(other); /// - [MethodImpl(InliningOptions.ShortMethod)] + [MethodImpl(MethodImplOptions.AggressiveInlining)] public override int GetHashCode() { if (this.boxedHighPrecisionPixel is null) @@ -326,15 +336,4 @@ public readonly partial struct Color : IEquatable return this.boxedHighPrecisionPixel.GetHashCode(); } - - [MethodImpl(InliningOptions.ShortMethod)] - private Vector4 ToScaledVector4() - { - if (this.boxedHighPrecisionPixel is null) - { - return this.data; - } - - return this.boxedHighPrecisionPixel.ToScaledVector4(); - } } diff --git a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs index f8734bb5a3..6598def2a5 100644 --- a/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs +++ b/src/ImageSharp/Formats/Gif/GifFrameMetadata.cs @@ -82,13 +82,13 @@ public class GifFrameMetadata : IDeepCloneable { // TODO: v4 How do I link the parent metadata to the frame metadata to get the global color table? int index = -1; - float background = 1f; + const float background = 1f; if (metadata.ColorTable.HasValue) { ReadOnlySpan colorTable = metadata.ColorTable.Value.Span; for (int i = 0; i < colorTable.Length; i++) { - Vector4 vector = (Vector4)colorTable[i]; + Vector4 vector = colorTable[i].ToScaledVector4(); if (vector.W < background) { index = i; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 993f53269d..113fef5957 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -4,6 +4,7 @@ using System.Buffers; using System.Buffers.Binary; using System.IO.Hashing; +using System.Numerics; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Common.Helpers; @@ -1559,7 +1560,24 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable { // We can use the color data from the decoded metadata here. // We avoid dithering by default to preserve the original colors. - this.derivedTransparencyIndex = metadata.ColorTable.Value.Span.IndexOf(Color.Transparent); + ReadOnlySpan palette = metadata.ColorTable.Value.Span; + + // Certain operations perform alpha premultiplication, which can cause the color to change so we + // must search for the transparency index in the palette. + // Transparent pixels are much more likely to be found at the end of a palette. + int index = -1; + for (int i = palette.Length - 1; i >= 0; i--) + { + Vector4 instance = palette[i].ToScaledVector4(); + if (instance.W == 0f) + { + index = i; + break; + } + } + + this.derivedTransparencyIndex = index; + this.quantizer = new PaletteQuantizer(metadata.ColorTable.Value, new() { Dither = null }, this.derivedTransparencyIndex); } else diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 63e6541354..63571617fb 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -311,18 +311,15 @@ internal class AlphaDecoder : IDisposable private static void HorizontalUnfilter(Span prev, Span input, Span dst, int width) { - if (Sse2.IsSupported) + // TODO: Investigate AdvSimd support for this method. + if (Sse2.IsSupported && width >= 9) { dst[0] = (byte)(input[0] + (prev.IsEmpty ? 0 : prev[0])); - if (width <= 1) - { - return; - } - nuint i; Vector128 last = Vector128.Zero.WithElement(0, dst[0]); ref byte srcRef = ref MemoryMarshal.GetReference(input); ref byte dstRef = ref MemoryMarshal.GetReference(dst); + for (i = 1; i <= (uint)width - 8; i += 8) { Vector128 a0 = Vector128.Create(Unsafe.As(ref Unsafe.Add(ref srcRef, i)), 0); diff --git a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs index 14a5a44f18..4247345c7b 100644 --- a/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs +++ b/tests/ImageSharp.Tests/Color/ColorTests.CastTo.cs @@ -105,7 +105,7 @@ public partial class ColorTests public void Vector4Constructor() { // Act: - Color color = (Color)Vector4.One; + Color color = Color.FromScaledVector(Vector4.One); // Assert: Assert.Equal(new RgbaVector(1, 1, 1, 1), color.ToPixel()); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 0fdd496308..a70fb86df1 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -8,6 +8,7 @@ using SixLabors.ImageSharp.Formats.Png; using SixLabors.ImageSharp.Formats.Webp; using SixLabors.ImageSharp.Metadata; using SixLabors.ImageSharp.PixelFormats; +using SixLabors.ImageSharp.Processing; using SixLabors.ImageSharp.Processing.Processors.Quantization; using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities.ImageComparison; @@ -679,6 +680,22 @@ public partial class PngEncoderTests encoded.CompareToReferenceOutput(ImageComparer.Exact, provider); } + // https://github.com/SixLabors/ImageSharp/issues/2469 + [Theory] + [WithFile(TestImages.Png.Issue2668, PixelTypes.Rgba32)] + public void Issue2668_Quantized_Encode_Alpha(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + image.Mutate(x => x.Resize(100, 100)); + + PngEncoder encoder = new() { BitDepth = PngBitDepth.Bit8, ColorType = PngColorType.Palette }; + + string actualOutputFile = provider.Utility.SaveTestOutputFile(image, "png", encoder); + using Image encoded = Image.Load(actualOutputFile); + encoded.CompareToReferenceOutput(ImageComparer.Exact, provider); + } + private static void TestPngEncoderCore( TestImageProvider provider, PngColorType pngColorType, diff --git a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs index c38b13075a..0dda304b64 100644 --- a/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/WebP/WebpDecoderTests.cs @@ -439,6 +439,17 @@ public class WebpDecoderTests image.CompareToOriginal(provider, ReferenceDecoder); } + // https://github.com/SixLabors/ImageSharp/issues/2670 + [Theory] + [WithFile(Lossy.Issue2670, PixelTypes.Rgba32)] + public void WebpDecoder_CanDecode_Issue2670(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(WebpDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider, ReferenceDecoder); + } + [Theory] [WithFile(Lossless.LossLessCorruptImage3, PixelTypes.Rgba32)] public void WebpDecoder_ThrowImageFormatException_OnInvalidImages(TestImageProvider provider) diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 933fcc4fae..022c3654a8 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -151,6 +151,9 @@ public static class TestImages // Issue 2447: https://github.com/SixLabors/ImageSharp/issues/2447 public const string Issue2447 = "Png/issues/issue_2447.png"; + // Issue 2668: https://github.com/SixLabors/ImageSharp/issues/2668 + public const string Issue2668 = "Png/issues/Issue_2668.png"; + public static class Bad { public const string MissingDataChunk = "Png/xdtn0g01.png"; @@ -806,6 +809,7 @@ public static class TestImages public const string Issue1594 = "Webp/issues/Issue1594.webp"; public const string Issue2243 = "Webp/issues/Issue2243.webp"; public const string Issue2257 = "Webp/issues/Issue2257.webp"; + public const string Issue2670 = "Webp/issues/Issue2670.webp"; } } diff --git a/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png new file mode 100644 index 0000000000..7af5391f70 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngEncoderTests/Issue2668_Quantized_Encode_Alpha_Rgba32_Issue_2668.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:f934af128b85b9e8f557d71ac8b1f1473a0922d0754fc0c4ece0d0e3d8d94c39 +size 7702 diff --git a/tests/Images/Input/Png/issues/Issue_2668.png b/tests/Images/Input/Png/issues/Issue_2668.png new file mode 100644 index 0000000000..2ca8c46171 --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2668.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:e8e5b2b933fd8fefd161f1d22970cb60247fd2d93b6c07b8b9ee1fdbc2241a3c +size 390225 diff --git a/tests/Images/Input/Webp/issues/Issue2670.webp b/tests/Images/Input/Webp/issues/Issue2670.webp new file mode 100644 index 0000000000..4dd1248986 --- /dev/null +++ b/tests/Images/Input/Webp/issues/Issue2670.webp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:23ad5eb449f693af68e51dd108a6b9847a8eb48b82ca5b848395a54c2e0be08f +size 152 From 8af9a8068e4b4f54a0a33438fc9937609f28ed79 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Robert=20Mutnia=C5=84ski?= Date: Wed, 28 Feb 2024 11:01:01 +0100 Subject: [PATCH 162/219] PR comments changes --- .../Formats/Jpeg/JpegDecoderCore.cs | 11 ++-- .../Formats/Jpeg/JpegEncoderCore.cs | 53 ++++++++++++------- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 23 ++++++++ 3 files changed, 65 insertions(+), 22 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index e43c20a7d9..cf5e449e71 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -523,13 +523,16 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals /// The remaining bytes in the segment block. private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) { - Span temp = new byte[markerContentByteSize]; + char[] temp = new char[markerContentByteSize]; JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); - stream.Read(temp); - string comment = Encoding.ASCII.GetString(temp); + for (int i = 0; i < markerContentByteSize; i++) + { + int read = stream.ReadByte(); + temp[i] = (char)read; + } - metadata.Comments.Add(JpegComData.FromString(comment)); + metadata.Comments.Add(new JpegComData(temp)); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index a55435c532..4ef4cea2d5 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -3,6 +3,7 @@ #nullable disable using System.Buffers.Binary; +using System.Collections; using System.Text; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; @@ -184,39 +185,55 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals return; } - for (int i = 0; i < metadata.Comments.Count; i++) + // We don't want to modify original metadata + List comments = new(metadata.Comments); + + int totalPayloadLength = 0; + for (int i = 0; i < comments.Count; i++) { - string comment = metadata.Comments[i].ToString(); + JpegComData comment = comments[i]; + ReadOnlyMemory currentComment = comment.Value; - if (comment.Length > maxCommentLength) + if (comment.Value.Length > maxCommentLength) { - string splitComment = comment.Substring(maxCommentLength, comment.Length - maxCommentLength); - metadata.Comments.Insert(i + 1, JpegComData.FromString(splitComment)); + ReadOnlyMemory splitComment = + currentComment.Slice(maxCommentLength, currentComment.Length - maxCommentLength); + comments.Insert(i + 1, new JpegComData(splitComment)); // We don't want to keep the extra bytes - comment = comment.Substring(0, maxCommentLength); + comments[i] = new JpegComData(currentComment.Slice(0, maxCommentLength)); } - int commentLength = comment.Length + 4; + totalPayloadLength += comment.Value.Length + 4; + } + + Span payload = new byte[totalPayloadLength]; + int currentCommentStartingIndex = 0; - Span commentSpan = new byte[commentLength]; - Span markers = commentSpan.Slice(0, 2); - Span payloadSize = commentSpan.Slice(2, 2); - Span payload = commentSpan.Slice(4, comment.Length); + for (int i = 0; i < comments.Count; i++) + { + ReadOnlyMemory comment = comments[i].Value; // Beginning of comment ff fe - markers[0] = JpegConstants.Markers.XFF; - markers[1] = JpegConstants.Markers.COM; + payload[currentCommentStartingIndex] = JpegConstants.Markers.XFF; + payload[currentCommentStartingIndex + 1] = JpegConstants.Markers.COM; // Write payload size - int comWithoutMarker = commentLength - 2; - payloadSize[0] = (byte)((comWithoutMarker >> 8) & 0xFF); - payloadSize[1] = (byte)(comWithoutMarker & 0xFF); + int comWithoutMarker = comment.Length + 2; + payload[currentCommentStartingIndex + 2] = (byte)((comWithoutMarker >> 8) & 0xFF); + payload[currentCommentStartingIndex + 3] = (byte)(comWithoutMarker & 0xFF); - Encoding.ASCII.GetBytes(comment, payload); + char[] commentChars = comment.ToArray(); + for (int j = 0; j < commentChars.Length; j++) + { + // Initial 4 bytes are always reserved + payload[4 + currentCommentStartingIndex + j] = (byte)commentChars[j]; + } - this.outputStream.Write(commentSpan, 0, commentSpan.Length); + currentCommentStartingIndex += comment.Length + 4; } + + this.outputStream.Write(payload, 0, payload.Length); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index e49afedbb5..f0593b462c 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -198,6 +198,29 @@ public partial class JpegEncoderTests Assert.Equal(meta.Comments.ElementAtOrDefault(1).ToString(), actual.Comments.ElementAtOrDefault(1).ToString()); } + [Fact] + public void Encode_SaveTooLongComment() + { + // arrange + string longString = new('c', 65534); + using var input = new Image(1, 1); + JpegMetadata meta = input.Metadata.GetJpegMetadata(); + using var memStream = new MemoryStream(); + + // act + meta.Comments.Add(JpegComData.FromString(longString)); + input.Save(memStream, JpegEncoder); + + // assert + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata actual = output.Metadata.GetJpegMetadata(); + Assert.NotEmpty(actual.Comments); + Assert.Equal(2, actual.Comments.Count); + Assert.Equal(longString[..65533], actual.Comments.ElementAtOrDefault(0).ToString()); + Assert.Equal("c", actual.Comments.ElementAtOrDefault(1).ToString()); + } + [Theory] [WithFile(TestImages.Jpeg.Baseline.Floorplan, PixelTypes.Rgb24, JpegEncodingColor.Luminance)] [WithFile(TestImages.Jpeg.Baseline.Jpeg444, PixelTypes.Rgb24, JpegEncodingColor.YCbCrRatio444)] From edc87ad90d4fcb0783c0c38be01a91a0dd26cd28 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 1 Mar 2024 20:18:35 +1000 Subject: [PATCH 163/219] Limit ancillary chunk size. --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 38 +++++++++---------- .../Formats/Png/PngDecoderOptions.cs | 6 +++ .../Formats/Png/PngDecoderTests.cs | 19 ++++++++++ tests/ImageSharp.Tests/TestImages.cs | 4 +- tests/Images/Input/Png/issues/bad-ztxt.png | 3 ++ tests/Images/Input/Png/issues/bad-ztxt2.png | 3 ++ 6 files changed, 52 insertions(+), 21 deletions(-) create mode 100644 tests/Images/Input/Png/issues/bad-ztxt.png create mode 100644 tests/Images/Input/Png/issues/bad-ztxt2.png diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 179bf38ba8..a96c53c104 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -120,6 +120,11 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// private readonly PngCrcChunkHandling pngCrcChunkHandling; + /// + /// The maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed. + /// + private readonly int maxUncompressedLength; + /// /// Initializes a new instance of the class. /// @@ -132,6 +137,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.skipMetadata = options.GeneralOptions.SkipMetadata; this.memoryAllocator = this.configuration.MemoryAllocator; this.pngCrcChunkHandling = options.PngCrcChunkHandling; + this.maxUncompressedLength = options.MaxUncompressedAncillaryChunkSizeBytes; } internal PngDecoderCore(PngDecoderOptions options, bool colorMetadataOnly) @@ -143,6 +149,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.configuration = options.GeneralOptions.Configuration; this.memoryAllocator = this.configuration.MemoryAllocator; this.pngCrcChunkHandling = options.PngCrcChunkHandling; + this.maxUncompressedLength = options.MaxUncompressedAncillaryChunkSizeBytes; } /// @@ -596,23 +603,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals private void InitializeImage(ImageMetadata metadata, FrameControl frameControl, out Image image) where TPixel : unmanaged, IPixel { - // When ignoring data CRCs, we can't use the image constructor that leaves the buffer uncleared. - if (this.pngCrcChunkHandling is PngCrcChunkHandling.IgnoreData or PngCrcChunkHandling.IgnoreAll) - { - image = new Image( - this.configuration, - this.header.Width, - this.header.Height, - metadata); - } - else - { - image = Image.CreateUninitialized( - this.configuration, - this.header.Width, - this.header.Height, - metadata); - } + image = new Image(this.configuration, this.header.Width, this.header.Height, metadata); PngFrameMetadata frameMetadata = image.Frames.RootFrame.Metadata.GetPngMetadata(); frameMetadata.FromChunk(in frameControl); @@ -1572,7 +1563,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals ReadOnlySpan compressedData = data[(zeroIndex + 2)..]; - if (this.TryDecompressZlibData(compressedData, out byte[] iccpProfileBytes)) + if (this.TryDecompressZlibData(compressedData, this.maxUncompressedLength, out byte[] iccpProfileBytes)) { metadata.IccProfile = new IccProfile(iccpProfileBytes); } @@ -1582,9 +1573,10 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// Tries to decompress zlib compressed data. /// /// The compressed data. + /// The maximum uncompressed length. /// The uncompressed bytes array. /// True, if de-compressing was successful. - private unsafe bool TryDecompressZlibData(ReadOnlySpan compressedData, out byte[] uncompressedBytesArray) + private unsafe bool TryDecompressZlibData(ReadOnlySpan compressedData, int maxLength, out byte[] uncompressedBytesArray) { fixed (byte* compressedDataBase = compressedData) { @@ -1604,6 +1596,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals int bytesRead = inflateStream.CompressedStream.Read(destUncompressedData, 0, destUncompressedData.Length); while (bytesRead != 0) { + if (memoryStreamOutput.Length > maxLength) + { + uncompressedBytesArray = Array.Empty(); + return false; + } + memoryStreamOutput.Write(destUncompressedData[..bytesRead]); bytesRead = inflateStream.CompressedStream.Read(destUncompressedData, 0, destUncompressedData.Length); } @@ -1746,7 +1744,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The . private bool TryDecompressTextData(ReadOnlySpan compressedData, Encoding encoding, [NotNullWhen(true)] out string? value) { - if (this.TryDecompressZlibData(compressedData, out byte[] uncompressedData)) + if (this.TryDecompressZlibData(compressedData, this.maxUncompressedLength, out byte[] uncompressedData)) { value = encoding.GetString(uncompressedData); return true; diff --git a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs index ab6ba4770e..abfa4b1da8 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderOptions.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderOptions.cs @@ -15,4 +15,10 @@ public sealed class PngDecoderOptions : ISpecializedDecoderOptions /// Gets a value indicating how to handle validation of any CRC (Cyclic Redundancy Check) data within the encoded PNG. /// public PngCrcChunkHandling PngCrcChunkHandling { get; init; } = PngCrcChunkHandling.IgnoreNonCritical; + + /// + /// Gets the maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed. + /// Defaults to 8MB + /// + public int MaxUncompressedAncillaryChunkSizeBytes { get; init; } = 8 * 1024 * 1024; // 8MB } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index b9f6075fb8..9b165526eb 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -672,4 +672,23 @@ public partial class PngDecoderTests string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, TestImages.Png.Issue2666)); using Image image = Image.Load(path); } + + [Theory] + + [InlineData(TestImages.Png.Bad.BadZTXT)] + [InlineData(TestImages.Png.Bad.BadZTXT2)] + public void Decode_BadZTXT(string file) + { + string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, file)); + using Image image = Image.Load(path); + } + + [Theory] + [InlineData(TestImages.Png.Bad.BadZTXT)] + [InlineData(TestImages.Png.Bad.BadZTXT2)] + public void Info_BadZTXT(string file) + { + string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, file)); + _ = Image.Identify(path); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index e72f6fad8d..00f7370f31 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -186,8 +186,10 @@ public static class TestImages // Invalid color type. public const string ColorTypeOne = "Png/xc1n0g08.png"; public const string ColorTypeNine = "Png/xc9n2c08.png"; - public const string FlagOfGermany0000016446 = "Png/issues/flag_of_germany-0000016446.png"; + + public const string BadZTXT = "Png/issues/bad-ztxt.png"; + public const string BadZTXT2 = "Png/issues/bad-ztxt2.png"; } } diff --git a/tests/Images/Input/Png/issues/bad-ztxt.png b/tests/Images/Input/Png/issues/bad-ztxt.png new file mode 100644 index 0000000000..710f888d0b --- /dev/null +++ b/tests/Images/Input/Png/issues/bad-ztxt.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:132a70cf0ac458a55cf4a44f4c6c025587491d304595835959955de6682fa472 +size 3913750 diff --git a/tests/Images/Input/Png/issues/bad-ztxt2.png b/tests/Images/Input/Png/issues/bad-ztxt2.png new file mode 100644 index 0000000000..958c00e3f0 --- /dev/null +++ b/tests/Images/Input/Png/issues/bad-ztxt2.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:778a5fc8e915d79e9f55e58c6e4f646ae55dd7e866e65960754cb67a2b445987 +size 93 From 3f22857a80c854791837333e3e5caca38d2d1363 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 1 Mar 2024 23:49:55 +1000 Subject: [PATCH 164/219] Allow nightlies from previous releases --- .github/workflows/build-and-test.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index b375574018..5a2e11266d 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -4,6 +4,7 @@ on: push: branches: - main + - release/* tags: - "v*" pull_request: From 0ac9f3db4daccc1b768d8f6b795a0f4da2f780f5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Mar 2024 17:35:04 +1000 Subject: [PATCH 165/219] Update AlphaDecoder.cs --- src/ImageSharp/Formats/Webp/AlphaDecoder.cs | 21 +++++++++++---------- 1 file changed, 11 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs index 63571617fb..eccd9ede8e 100644 --- a/src/ImageSharp/Formats/Webp/AlphaDecoder.cs +++ b/src/ImageSharp/Formats/Webp/AlphaDecoder.cs @@ -6,7 +6,9 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using System.Runtime.Intrinsics; +using System.Runtime.Intrinsics.Arm; using System.Runtime.Intrinsics.X86; +using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Memory; @@ -311,8 +313,7 @@ internal class AlphaDecoder : IDisposable private static void HorizontalUnfilter(Span prev, Span input, Span dst, int width) { - // TODO: Investigate AdvSimd support for this method. - if (Sse2.IsSupported && width >= 9) + if ((Sse2.IsSupported || AdvSimd.IsSupported) && width >= 9) { dst[0] = (byte)(input[0] + (prev.IsEmpty ? 0 : prev[0])); nuint i; @@ -323,17 +324,17 @@ internal class AlphaDecoder : IDisposable for (i = 1; i <= (uint)width - 8; i += 8) { Vector128 a0 = Vector128.Create(Unsafe.As(ref Unsafe.Add(ref srcRef, i)), 0); - Vector128 a1 = Sse2.Add(a0.AsByte(), last.AsByte()); - Vector128 a2 = Sse2.ShiftLeftLogical128BitLane(a1, 1); - Vector128 a3 = Sse2.Add(a1, a2); - Vector128 a4 = Sse2.ShiftLeftLogical128BitLane(a3, 2); - Vector128 a5 = Sse2.Add(a3, a4); - Vector128 a6 = Sse2.ShiftLeftLogical128BitLane(a5, 4); - Vector128 a7 = Sse2.Add(a5, a6); + Vector128 a1 = a0.AsByte() + last.AsByte(); + Vector128 a2 = Vector128Utilities.ShiftLeftBytesInVector(a1, 1); + Vector128 a3 = a1 + a2; + Vector128 a4 = Vector128Utilities.ShiftLeftBytesInVector(a3, 2); + Vector128 a5 = a3 + a4; + Vector128 a6 = Vector128Utilities.ShiftLeftBytesInVector(a5, 4); + Vector128 a7 = a5 + a6; ref byte outputRef = ref Unsafe.Add(ref dstRef, i); Unsafe.As>(ref outputRef) = a7.GetLower(); - last = Sse2.ShiftRightLogical(a7.AsInt64(), 56).AsInt32(); + last = Vector128.ShiftRightLogical(a7.AsInt64(), 56).AsInt32(); } for (; i < (uint)width; ++i) From 8bf86986a45d2e36fbd74a68bbd7dea65195ad90 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Thu, 7 Mar 2024 19:41:24 +1000 Subject: [PATCH 166/219] Update PngDecoderCore.cs --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 194ee16615..6a321a3ba0 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -125,7 +125,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// A reusable Crc32 hashing instance. /// private readonly Crc32 crc32 = new(); - + + /// /// The maximum memory in bytes that a zTXt, sPLT, iTXt, iCCP, or unknown chunk can occupy when decompressed. /// private readonly int maxUncompressedLength; From d8484da7399659a78c044545589a4c5ec67bbda0 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 13 Mar 2024 15:10:20 +1000 Subject: [PATCH 167/219] Remove allocations and cleanup. --- src/ImageSharp/Formats/Jpeg/JpegComData.cs | 24 ++-- .../Formats/Jpeg/JpegDecoderCore.cs | 9 +- .../Formats/Jpeg/JpegEncoderCore.cs | 77 +++++-------- .../Formats/Jpg/JpegEncoderTests.Metadata.cs | 104 ++++++++---------- 4 files changed, 92 insertions(+), 122 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/JpegComData.cs b/src/ImageSharp/Formats/Jpeg/JpegComData.cs index 26ade0217f..4e832d9030 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegComData.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegComData.cs @@ -1,32 +1,32 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Formats.Jpeg; /// -/// Contains JPEG comment +/// Represents a JPEG comment /// public readonly struct JpegComData { - /// - /// Converts string to - /// - /// The comment string. - /// The - public static JpegComData FromString(string value) => new(value.AsMemory()); - /// /// Initializes a new instance of the struct. /// - /// The comment ReadOnlyMemory of chars. + /// The comment buffer. public JpegComData(ReadOnlyMemory value) => this.Value = value; + /// + /// Gets the value. + /// public ReadOnlyMemory Value { get; } /// - /// Converts Value to string + /// Converts string to /// - /// The comment string. + /// The comment string. + /// The + public static JpegComData FromString(string value) => new(value.AsMemory()); + + /// public override string ToString() => this.Value.ToString(); } diff --git a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs index cf5e449e71..906505b76a 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegDecoderCore.cs @@ -6,7 +6,6 @@ using System.Buffers; using System.Buffers.Binary; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; -using System.Text; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Decoder; @@ -481,6 +480,8 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals break; case JpegConstants.Markers.APP15: + stream.Skip(markerContentByteSize); + break; case JpegConstants.Markers.COM: this.ProcessComMarker(stream, markerContentByteSize); break; @@ -523,16 +524,16 @@ internal sealed class JpegDecoderCore : IRawJpegData, IImageDecoderInternals /// The remaining bytes in the segment block. private void ProcessComMarker(BufferedReadStream stream, int markerContentByteSize) { - char[] temp = new char[markerContentByteSize]; + char[] chars = new char[markerContentByteSize]; JpegMetadata metadata = this.Metadata.GetFormatMetadata(JpegFormat.Instance); for (int i = 0; i < markerContentByteSize; i++) { int read = stream.ReadByte(); - temp[i] = (char)read; + chars[i] = (char)read; } - metadata.Comments.Add(new JpegComData(temp)); + metadata.Comments.Add(new JpegComData(chars)); } /// diff --git a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs index 4ef4cea2d5..243bbe051d 100644 --- a/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs +++ b/src/ImageSharp/Formats/Jpeg/JpegEncoderCore.cs @@ -2,9 +2,8 @@ // Licensed under the Six Labors Split License. #nullable disable +using System.Buffers; using System.Buffers.Binary; -using System.Collections; -using System.Text; using SixLabors.ImageSharp.Common.Helpers; using SixLabors.ImageSharp.Formats.Jpeg.Components; using SixLabors.ImageSharp.Formats.Jpeg.Components.Encoder; @@ -27,6 +26,9 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals /// private static readonly JpegFrameConfig[] FrameConfigs = CreateFrameConfigs(); + /// + /// The current calling encoder. + /// private readonly JpegEncoder encoder; /// @@ -92,7 +94,7 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals this.WriteProfiles(metadata, buffer); // Write comments - this.WriteComment(jpegMetadata); + this.WriteComments(image.Configuration, jpegMetadata); // Write the image dimensions. this.WriteStartOfFrame(image.Width, image.Height, frameConfig, buffer); @@ -173,67 +175,48 @@ internal sealed unsafe partial class JpegEncoderCore : IImageEncoderInternals } /// - /// Writes comment + /// Writes the COM tags. /// + /// The configuration. /// The image metadata. - private void WriteComment(JpegMetadata metadata) + private void WriteComments(Configuration configuration, JpegMetadata metadata) { - int maxCommentLength = 65533; - if (metadata.Comments.Count == 0) { return; } - // We don't want to modify original metadata - List comments = new(metadata.Comments); - - int totalPayloadLength = 0; - for (int i = 0; i < comments.Count; i++) + const int maxCommentLength = 65533; + using IMemoryOwner bufferOwner = configuration.MemoryAllocator.Allocate(maxCommentLength); + Span buffer = bufferOwner.Memory.Span; + foreach (JpegComData comment in metadata.Comments) { - JpegComData comment = comments[i]; - ReadOnlyMemory currentComment = comment.Value; - - if (comment.Value.Length > maxCommentLength) + int totalLength = comment.Value.Length; + if (totalLength == 0) { - ReadOnlyMemory splitComment = - currentComment.Slice(maxCommentLength, currentComment.Length - maxCommentLength); - comments.Insert(i + 1, new JpegComData(splitComment)); - - // We don't want to keep the extra bytes - comments[i] = new JpegComData(currentComment.Slice(0, maxCommentLength)); + continue; } - totalPayloadLength += comment.Value.Length + 4; - } - - Span payload = new byte[totalPayloadLength]; - int currentCommentStartingIndex = 0; - - for (int i = 0; i < comments.Count; i++) - { - ReadOnlyMemory comment = comments[i].Value; + // Loop through and split the comment into multiple comments if the comment length + // is greater than the maximum allowed length. + while (totalLength > 0) + { + int currentLength = Math.Min(totalLength, maxCommentLength); - // Beginning of comment ff fe - payload[currentCommentStartingIndex] = JpegConstants.Markers.XFF; - payload[currentCommentStartingIndex + 1] = JpegConstants.Markers.COM; + // Write the marker header. + this.WriteMarkerHeader(JpegConstants.Markers.COM, currentLength + 2, buffer); - // Write payload size - int comWithoutMarker = comment.Length + 2; - payload[currentCommentStartingIndex + 2] = (byte)((comWithoutMarker >> 8) & 0xFF); - payload[currentCommentStartingIndex + 3] = (byte)(comWithoutMarker & 0xFF); + ReadOnlySpan commentValue = comment.Value.Span.Slice(comment.Value.Length - totalLength, currentLength); + for (int i = 0; i < commentValue.Length; i++) + { + buffer[i] = (byte)commentValue[i]; + } - char[] commentChars = comment.ToArray(); - for (int j = 0; j < commentChars.Length; j++) - { - // Initial 4 bytes are always reserved - payload[4 + currentCommentStartingIndex + j] = (byte)commentChars[j]; + // Write the comment. + this.outputStream.Write(buffer, 0, currentLength); + totalLength -= currentLength; } - - currentCommentStartingIndex += comment.Length + 4; } - - this.outputStream.Write(payload, 0, payload.Length); } /// diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs index f0593b462c..f06fbe9635 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegEncoderTests.Metadata.cs @@ -32,19 +32,19 @@ public partial class JpegEncoderTests public void Encode_PreservesIptcProfile() { // arrange - using var input = new Image(1, 1); - var expectedProfile = new IptcProfile(); + using Image input = new(1, 1); + IptcProfile expectedProfile = new(); expectedProfile.SetValue(IptcTag.Country, "ESPAÑA"); expectedProfile.SetValue(IptcTag.City, "unit-test-city"); input.Metadata.IptcProfile = expectedProfile; // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); IptcProfile actual = output.Metadata.IptcProfile; Assert.NotNull(actual); IEnumerable values = expectedProfile.Values; @@ -55,17 +55,17 @@ public partial class JpegEncoderTests public void Encode_PreservesExifProfile() { // arrange - using var input = new Image(1, 1); + using Image input = new(1, 1); input.Metadata.ExifProfile = new ExifProfile(); input.Metadata.ExifProfile.SetValue(ExifTag.Software, "unit_test"); // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); ExifProfile actual = output.Metadata.ExifProfile; Assert.NotNull(actual); IReadOnlyList values = input.Metadata.ExifProfile.Values; @@ -76,16 +76,16 @@ public partial class JpegEncoderTests public void Encode_PreservesIccProfile() { // arrange - using var input = new Image(1, 1); + using Image input = new(1, 1); input.Metadata.IccProfile = new IccProfile(IccTestDataProfiles.Profile_Random_Array); // act - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); input.Save(memStream, JpegEncoder); // assert memStream.Position = 0; - using var output = Image.Load(memStream); + using Image output = Image.Load(memStream); IccProfile actual = output.Metadata.IccProfile; Assert.NotNull(actual); IccProfile values = input.Metadata.IccProfile; @@ -99,12 +99,10 @@ public partial class JpegEncoderTests { Exception ex = Record.Exception(() => { - var encoder = new JpegEncoder(); - using (var stream = new MemoryStream()) - { - using Image image = provider.GetImage(JpegDecoder.Instance); - image.Save(stream, encoder); - } + JpegEncoder encoder = new(); + using MemoryStream stream = new(); + using Image image = provider.GetImage(JpegDecoder.Instance); + image.Save(stream, encoder); }); Assert.Null(ex); @@ -114,23 +112,17 @@ public partial class JpegEncoderTests [MemberData(nameof(RatioFiles))] public void Encode_PreserveRatio(string imagePath, int xResolution, int yResolution, PixelResolutionUnit resolutionUnit) { - var testFile = TestFile.Create(imagePath); - using (Image input = testFile.CreateRgba32Image()) - { - using (var memStream = new MemoryStream()) - { - input.Save(memStream, JpegEncoder); - - memStream.Position = 0; - using (var output = Image.Load(memStream)) - { - ImageMetadata meta = output.Metadata; - Assert.Equal(xResolution, meta.HorizontalResolution); - Assert.Equal(yResolution, meta.VerticalResolution); - Assert.Equal(resolutionUnit, meta.ResolutionUnits); - } - } - } + TestFile testFile = TestFile.Create(imagePath); + using Image input = testFile.CreateRgba32Image(); + using MemoryStream memStream = new(); + input.Save(memStream, JpegEncoder); + + memStream.Position = 0; + using Image output = Image.Load(memStream); + ImageMetadata meta = output.Metadata; + Assert.Equal(xResolution, meta.HorizontalResolution); + Assert.Equal(yResolution, meta.VerticalResolution); + Assert.Equal(resolutionUnit, meta.ResolutionUnits); } [Theory] @@ -138,20 +130,14 @@ public partial class JpegEncoderTests public void Encode_PreservesQuality(string imagePath, int quality) { TestFile testFile = TestFile.Create(imagePath); - using (Image input = testFile.CreateRgba32Image()) - { - using (var memStream = new MemoryStream()) - { - input.Save(memStream, JpegEncoder); - - memStream.Position = 0; - using (var output = Image.Load(memStream)) - { - JpegMetadata meta = output.Metadata.GetJpegMetadata(); - Assert.Equal(quality, meta.Quality); - } - } - } + using Image input = testFile.CreateRgba32Image(); + using MemoryStream memStream = new(); + input.Save(memStream, JpegEncoder); + + memStream.Position = 0; + using Image output = Image.Load(memStream); + JpegMetadata meta = output.Metadata.GetJpegMetadata(); + Assert.Equal(quality, meta.Quality); } [Theory] @@ -161,7 +147,7 @@ public partial class JpegEncoderTests { // arrange using Image input = provider.GetImage(JpegDecoder.Instance); - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); // act input.Save(memStream, JpegEncoder); @@ -172,16 +158,16 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(1, actual.Comments.Count); - Assert.Equal("TEST COMMENT", actual.Comments.ElementAtOrDefault(0).ToString()); + Assert.Equal("TEST COMMENT", actual.Comments[0].ToString()); } [Fact] public void Encode_SavesMultipleComments() { // arrange - using var input = new Image(1, 1); + using Image input = new(1, 1); JpegMetadata meta = input.Metadata.GetJpegMetadata(); - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); // act meta.Comments.Add(JpegComData.FromString("First comment")); @@ -194,8 +180,8 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(2, actual.Comments.Count); - Assert.Equal(meta.Comments.ElementAtOrDefault(0).ToString(), actual.Comments.ElementAtOrDefault(0).ToString()); - Assert.Equal(meta.Comments.ElementAtOrDefault(1).ToString(), actual.Comments.ElementAtOrDefault(1).ToString()); + Assert.Equal(meta.Comments[0].ToString(), actual.Comments[0].ToString()); + Assert.Equal(meta.Comments[1].ToString(), actual.Comments[1].ToString()); } [Fact] @@ -203,9 +189,9 @@ public partial class JpegEncoderTests { // arrange string longString = new('c', 65534); - using var input = new Image(1, 1); + using Image input = new(1, 1); JpegMetadata meta = input.Metadata.GetJpegMetadata(); - using var memStream = new MemoryStream(); + using MemoryStream memStream = new(); // act meta.Comments.Add(JpegComData.FromString(longString)); @@ -217,8 +203,8 @@ public partial class JpegEncoderTests JpegMetadata actual = output.Metadata.GetJpegMetadata(); Assert.NotEmpty(actual.Comments); Assert.Equal(2, actual.Comments.Count); - Assert.Equal(longString[..65533], actual.Comments.ElementAtOrDefault(0).ToString()); - Assert.Equal("c", actual.Comments.ElementAtOrDefault(1).ToString()); + Assert.Equal(longString[..65533], actual.Comments[0].ToString()); + Assert.Equal("c", actual.Comments[1].ToString()); } [Theory] @@ -231,14 +217,14 @@ public partial class JpegEncoderTests { // arrange using Image input = provider.GetImage(JpegDecoder.Instance); - using var memoryStream = new MemoryStream(); + using MemoryStream memoryStream = new(); // act input.Save(memoryStream, JpegEncoder); // assert memoryStream.Position = 0; - using var output = Image.Load(memoryStream); + using Image output = Image.Load(memoryStream); JpegMetadata meta = output.Metadata.GetJpegMetadata(); Assert.Equal(expectedColorType, meta.ColorType); } From 58e8efac20aa0c9eee16ad8d1451c81069e89df3 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Mar 2024 20:02:00 +1000 Subject: [PATCH 168/219] Ensure VP8X alpha flag is updated correctly. --- src/ImageSharp/Common/Helpers/RiffHelper.cs | 17 +++++++++++- .../Formats/Webp/BitWriter/BitWriterBase.cs | 26 +++++++++++++----- .../Formats/Webp/Chunks/WebpVp8X.cs | 23 +++++++++++++++- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 20 +++++++++----- .../Formats/Webp/Lossy/Vp8Encoder.cs | 24 +++++++++++------ .../Formats/Webp/WebpChunkParsingUtils.cs | 1 - .../Formats/Webp/WebpDecoderCore.cs | 2 +- .../Formats/Webp/WebpEncoderCore.cs | 27 ++++++++++++------- 8 files changed, 105 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Common/Helpers/RiffHelper.cs b/src/ImageSharp/Common/Helpers/RiffHelper.cs index 8f06e5886f..667a47fc94 100644 --- a/src/ImageSharp/Common/Helpers/RiffHelper.cs +++ b/src/ImageSharp/Common/Helpers/RiffHelper.cs @@ -3,6 +3,7 @@ using System.Buffers.Binary; using System.Text; +using SixLabors.ImageSharp.Formats.Webp.Chunks; namespace SixLabors.ImageSharp.Common.Helpers; @@ -107,6 +108,7 @@ internal static class RiffHelper position++; } + // Add the size of the encoded file to the Riff header. BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); stream.Position = sizePosition; stream.Write(buffer); @@ -120,5 +122,18 @@ internal static class RiffHelper return sizePosition; } - public static void EndWriteRiffFile(Stream stream, long sizePosition) => EndWriteChunk(stream, sizePosition); + public static void EndWriteRiffFile(Stream stream, in WebpVp8X vp8x, bool updateVp8x, long sizePosition) + { + EndWriteChunk(stream, sizePosition + 4); + + // Write the VP8X chunk if necessary. + if (updateVp8x) + { + long position = stream.Position; + + stream.Position = sizePosition + 12; + vp8x.WriteTo(stream); + stream.Position = position; + } + } } diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 9ffda0f51f..651e68011f 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -88,7 +88,8 @@ internal abstract class BitWriterBase /// The color profile. /// Flag indicating, if a alpha channel is present. /// Flag indicating, if an animation parameter is present. - public static void WriteTrunksBeforeData( + /// A or a default instance. + public static WebpVp8X WriteTrunksBeforeData( Stream stream, uint width, uint height, @@ -102,16 +103,19 @@ internal abstract class BitWriterBase RiffHelper.BeginWriteRiffFile(stream, WebpConstants.WebpFourCc); // Write VP8X, header if necessary. + WebpVp8X vp8x = default; bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha || hasAnimation; if (isVp8X) { - WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha, hasAnimation); + vp8x = WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha, hasAnimation); if (iccProfile != null) { RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Iccp, iccProfile.ToByteArray()); } } + + return vp8x; } /// @@ -124,10 +128,16 @@ internal abstract class BitWriterBase /// Write the trunks after data trunk. /// /// The stream to write to. - /// The exif profile. + /// The VP8X chunk. + /// Whether to update the chunk. + /// The initial position of the stream before encoding. + /// The EXIF profile. /// The XMP profile. public static void WriteTrunksAfterData( Stream stream, + in WebpVp8X vp8x, + bool updateVp8x, + long initialPosition, ExifProfile? exifProfile, XmpProfile? xmpProfile) { @@ -141,7 +151,7 @@ internal abstract class BitWriterBase RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Xmp, xmpProfile.Data); } - RiffHelper.EndWriteRiffFile(stream, 4); + RiffHelper.EndWriteRiffFile(stream, in vp8x, updateVp8x, initialPosition); } /// @@ -186,19 +196,21 @@ internal abstract class BitWriterBase /// Writes a VP8X header to the stream. /// /// The stream to write to. - /// A exif profile or null, if it does not exist. - /// A XMP profile or null, if it does not exist. + /// An EXIF profile or null, if it does not exist. + /// An XMP profile or null, if it does not exist. /// The color profile. /// The width of the image. /// The height of the image. /// Flag indicating, if a alpha channel is present. /// Flag indicating, if an animation parameter is present. - protected static void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) + protected static WebpVp8X WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) { WebpVp8X chunk = new(hasAnimation, xmpProfile != null, exifProfile != null, hasAlpha, iccProfile != null, width, height); chunk.Validate(MaxDimension, MaxCanvasPixels); chunk.WriteTo(stream); + + return chunk; } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index 70d6870ce4..41fe4dd072 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -5,7 +5,7 @@ using SixLabors.ImageSharp.Common.Helpers; namespace SixLabors.ImageSharp.Formats.Webp.Chunks; -internal readonly struct WebpVp8X +internal readonly struct WebpVp8X : IEquatable { public WebpVp8X(bool hasAnimation, bool hasXmp, bool hasExif, bool hasAlpha, bool hasIcc, uint width, uint height) { @@ -53,6 +53,24 @@ internal readonly struct WebpVp8X /// public uint Height { get; } + public static bool operator ==(WebpVp8X left, WebpVp8X right) => left.Equals(right); + + public static bool operator !=(WebpVp8X left, WebpVp8X right) => !(left == right); + + public override bool Equals(object? obj) => obj is WebpVp8X x && this.Equals(x); + + public bool Equals(WebpVp8X other) + => this.HasAnimation == other.HasAnimation + && this.HasXmp == other.HasXmp + && this.HasExif == other.HasExif + && this.HasAlpha == other.HasAlpha + && this.HasIcc == other.HasIcc + && this.Width == other.Width + && this.Height == other.Height; + + public override int GetHashCode() + => HashCode.Combine(this.HasAnimation, this.HasXmp, this.HasExif, this.HasAlpha, this.HasIcc, this.Width, this.Height); + public void Validate(uint maxDimension, ulong maxCanvasPixels) { if (this.Width > maxDimension || this.Height > maxDimension) @@ -67,6 +85,9 @@ internal readonly struct WebpVp8X } } + public WebpVp8X WithAlpha(bool hasAlpha) + => new(this.HasAnimation, this.HasXmp, this.HasExif, hasAlpha, this.HasIcc, this.Width, this.Height); + public void WriteTo(Stream stream) { byte flags = 0; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index 518c09ff4d..485225ab89 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -237,7 +237,7 @@ internal class Vp8LEncoder : IDisposable /// public Vp8LHashChain HashChain { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAnimation) + public WebpVp8X EncodeHeader(Image image, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bit-writer buffer to the stream. @@ -247,7 +247,8 @@ internal class Vp8LEncoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksBeforeData( + // The alpha flag is updated following encoding. + WebpVp8X vp8x = BitWriterBase.WriteTrunksBeforeData( stream, (uint)image.Width, (uint)image.Height, @@ -262,9 +263,11 @@ internal class Vp8LEncoder : IDisposable WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } + + return vp8x; } - public void EncodeFooter(Image image, Stream stream) + public void EncodeFooter(Image image, in WebpVp8X vp8x, bool hasAlpha, Stream stream, long initialPosition) where TPixel : unmanaged, IPixel { // Write bytes from the bit-writer buffer to the stream. @@ -273,7 +276,9 @@ internal class Vp8LEncoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + bool updateVp8x = hasAlpha && vp8x != default; + WebpVp8X updated = updateVp8x ? vp8x.WithAlpha(true) : vp8x; + BitWriterBase.WriteTrunksAfterData(stream, in updated, updateVp8x, initialPosition, exifProfile, xmpProfile); } /// @@ -285,7 +290,8 @@ internal class Vp8LEncoder : IDisposable /// The frame metadata. /// The to encode the image data to. /// Flag indicating, if an animation parameter is present. - public void Encode(ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, Stream stream, bool hasAnimation) + /// A indicating whether the frame contains an alpha channel. + public bool Encode(ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { // Convert image pixels to bgra array. @@ -324,6 +330,8 @@ internal class Vp8LEncoder : IDisposable { RiffHelper.EndWriteChunk(stream, prevPosition); } + + return hasAlpha; } /// @@ -502,7 +510,7 @@ internal class Vp8LEncoder : IDisposable /// The type of the pixels. /// The frame pixel buffer to convert. /// true, if the image is non opaque. - private bool ConvertPixelsToBgra(Buffer2DRegion pixels) + public bool ConvertPixelsToBgra(Buffer2DRegion pixels) where TPixel : unmanaged, IPixel { bool nonOpaque = false; diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 2b74c300a4..7317527f72 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -311,7 +311,7 @@ internal class Vp8Encoder : IDisposable /// private int MbHeaderLimit { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation) + public WebpVp8X EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -321,7 +321,7 @@ internal class Vp8Encoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksBeforeData( + WebpVp8X vp8x = BitWriterBase.WriteTrunksBeforeData( stream, (uint)image.Width, (uint)image.Height, @@ -336,9 +336,11 @@ internal class Vp8Encoder : IDisposable WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } + + return vp8x; } - public void EncodeFooter(Image image, Stream stream) + public void EncodeFooter(Image image, in WebpVp8X vp8x, bool hasAlpha, Stream stream, long initialPosition) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -347,7 +349,9 @@ internal class Vp8Encoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + bool updateVp8x = hasAlpha && vp8x != default; + WebpVp8X updated = updateVp8x ? vp8x.WithAlpha(true) : vp8x; + BitWriterBase.WriteTrunksAfterData(stream, in updated, updateVp8x, initialPosition, exifProfile, xmpProfile); } /// @@ -358,9 +362,10 @@ internal class Vp8Encoder : IDisposable /// The stream to encode the image data to. /// The region of interest within the frame to encode. /// The frame metadata. - public void EncodeAnimation(ImageFrame frame, Stream stream, Rectangle bounds, WebpFrameMetadata frameMetadata) - where TPixel : unmanaged, IPixel => - this.Encode(stream, frame, bounds, frameMetadata, true, null); + /// A indicating whether the frame contains an alpha channel. + public bool EncodeAnimation(ImageFrame frame, Stream stream, Rectangle bounds, WebpFrameMetadata frameMetadata) + where TPixel : unmanaged, IPixel + => this.Encode(stream, frame, bounds, frameMetadata, true, null); /// /// Encodes the static image frame to the specified stream. @@ -385,7 +390,8 @@ internal class Vp8Encoder : IDisposable /// The frame metadata. /// Flag indicating, if an animation parameter is present. /// The image to encode from. - private void Encode(Stream stream, ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, bool hasAnimation, Image image) + /// A indicating whether the frame contains an alpha channel. + private bool Encode(Stream stream, ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, bool hasAnimation, Image image) where TPixel : unmanaged, IPixel { int width = bounds.Width; @@ -515,6 +521,8 @@ internal class Vp8Encoder : IDisposable { encodedAlphaData?.Dispose(); } + + return hasAlpha; } /// diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index 80ffe8a996..07f09d45ea 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; -using System.Drawing; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 69a0afcd9b..21a25860c7 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -54,7 +54,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable /// /// The flag to decide how to handle the background color in the Animation Chunk. /// - private BackgroundColorHandling backgroundColorHandling; + private readonly BackgroundColorHandling backgroundColorHandling; /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index e37c1d1796..d29759f9a1 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; @@ -143,12 +144,14 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - encoder.EncodeHeader(image, stream, hasAnimation); + long initialPosition = stream.Position; + bool hasAlpha = false; + WebpVp8X vp8x = encoder.EncodeHeader(image, stream, hasAnimation); // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); - encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); + hasAlpha |= encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); if (hasAnimation) { @@ -190,14 +193,14 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - animatedEncoder.Encode(encodingFrame, bounds, frameMetadata, stream, hasAnimation); + hasAlpha |= animatedEncoder.Encode(encodingFrame, bounds, frameMetadata, stream, hasAnimation); previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } } - encoder.EncodeFooter(image, stream); + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } else { @@ -214,17 +217,20 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.spatialNoiseShaping, this.alphaCompression); + long initialPosition = stream.Position; + bool hasAlpha = false; + WebpVp8X vp8x = default; if (image.Frames.Count > 1) { - // TODO: What about alpha here? - encoder.EncodeHeader(image, stream, false, true); + // The alpha flag is updated following encoding. + vp8x = encoder.EncodeHeader(image, stream, false, true); // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; - encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); + hasAlpha |= encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); // Encode additional frames // This frame is reused to store de-duplicated pixel buffers. @@ -263,18 +269,19 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.spatialNoiseShaping, this.alphaCompression); - animatedEncoder.EncodeAnimation(encodingFrame, stream, bounds, frameMetadata); + hasAlpha |= animatedEncoder.EncodeAnimation(encodingFrame, stream, bounds, frameMetadata); previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } + + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } else { encoder.EncodeStatic(stream, image); + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } - - encoder.EncodeFooter(image, stream); } } } From a197f222a685b3e4b08bf7d83e06cc95b68f09ee Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 17 Mar 2024 11:05:56 +1000 Subject: [PATCH 169/219] Update WebpVp8X.cs --- src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index 41fe4dd072..fc88f8faad 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -68,7 +68,7 @@ internal readonly struct WebpVp8X : IEquatable && this.Width == other.Width && this.Height == other.Height; - public override int GetHashCode() + public override int GetHashCode() => HashCode.Combine(this.HasAnimation, this.HasXmp, this.HasExif, this.HasAlpha, this.HasIcc, this.Width, this.Height); public void Validate(uint maxDimension, ulong maxCanvasPixels) From 382ee7fb2351979a194684707491a88a22a9070b Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:30:20 +1000 Subject: [PATCH 170/219] Only exit after multiple EOF hits --- .../Jpeg/Components/Decoder/JpegBitReader.cs | 20 +++++++++++++++---- .../Formats/Jpg/JpegDecoderTests.cs | 11 ++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/issues/Issue2638.jpg | 3 +++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/Issue2638.jpg diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index 0877dbc922..c2b0cb6e07 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -22,6 +22,9 @@ internal struct JpegBitReader // Whether there is no more good data to pull from the stream for the current mcu. private bool badData; + // How many times have we hit the eof. + private int eofHitCount; + public JpegBitReader(BufferedReadStream stream) { this.stream = stream; @@ -31,6 +34,7 @@ internal struct JpegBitReader this.MarkerPosition = 0; this.badData = false; this.NoData = false; + this.eofHitCount = 0; } /// @@ -80,6 +84,9 @@ internal struct JpegBitReader [MethodImpl(InliningOptions.ShortMethod)] public bool HasBadMarker() => this.Marker != JpegConstants.Markers.XFF && !this.HasRestartMarker(); + [MethodImpl(InliningOptions.ShortMethod)] + public bool HasEndMarker() => this.Marker == JpegConstants.Markers.EOI; + [MethodImpl(InliningOptions.AlwaysInline)] public void FillBuffer() { @@ -219,11 +226,16 @@ internal struct JpegBitReader // we know we have hit the EOI and completed decoding the scan buffer. if (value == -1 || (this.badData && this.data == 0 && this.stream.Position >= this.stream.Length)) { - // We've encountered the end of the file stream which means there's no EOI marker + // We've passed the end of the file stream which means there's no EOI marker // in the image or the SOS marker has the wrong dimensions set. - this.badData = true; - this.NoData = true; - value = 0; + if (this.eofHitCount > JpegConstants.Huffman.FetchLoop) + { + this.badData = true; + this.NoData = true; + value = 0; + } + + this.eofHitCount++; } return value; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index c8d93f6e9e..6a94a98ac6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -364,4 +364,15 @@ public partial class JpegDecoderTests image.DebugSave(provider); image.CompareToOriginal(provider); } + + // https://github.com/SixLabors/ImageSharp/issues/2638 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2638, PixelTypes.Rgba32)] + public void Issue2638_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 6be8ff6a68..5da581e52f 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -316,6 +316,7 @@ public static class TestImages public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; public const string Issue2067_CommentMarker = "Jpg/issues/issue-2067-comment.jpg"; + public const string Issue2638 = "Jpg/issues/Issue2638.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/Issue2638.jpg b/tests/Images/Input/Jpg/issues/Issue2638.jpg new file mode 100644 index 0000000000..f42d67b0e8 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue2638.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:208d5b0b727bbef120a7e090e020a48f99c9e264c2d3939ba749f8620853c1fe +size 70876 From 45bc54ac4486ada9c0fe3b9ec35f33f23c174ce5 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:31:57 +1000 Subject: [PATCH 171/219] Remove unused code. --- .../Formats/Jpeg/Components/Decoder/JpegBitReader.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index c2b0cb6e07..babd2ff4df 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -84,9 +84,6 @@ internal struct JpegBitReader [MethodImpl(InliningOptions.ShortMethod)] public bool HasBadMarker() => this.Marker != JpegConstants.Markers.XFF && !this.HasRestartMarker(); - [MethodImpl(InliningOptions.ShortMethod)] - public bool HasEndMarker() => this.Marker == JpegConstants.Markers.EOI; - [MethodImpl(InliningOptions.AlwaysInline)] public void FillBuffer() { From 8acecdaf3d1d7796c606667f856f79111f2506bb Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:35:23 +1000 Subject: [PATCH 172/219] Update comment --- src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index babd2ff4df..e71d86a1d9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -223,7 +223,7 @@ internal struct JpegBitReader // we know we have hit the EOI and completed decoding the scan buffer. if (value == -1 || (this.badData && this.data == 0 && this.stream.Position >= this.stream.Length)) { - // We've passed the end of the file stream which means there's no EOI marker + // We've hit the end of the file stream more times than allowed which means there's no EOI marker // in the image or the SOS marker has the wrong dimensions set. if (this.eofHitCount > JpegConstants.Huffman.FetchLoop) { From 623ad5defdbf8b62fe9c5fd2d1fc05e1be674316 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:30:20 +1000 Subject: [PATCH 173/219] Only exit after multiple EOF hits --- .../Jpeg/Components/Decoder/JpegBitReader.cs | 20 +++++++++++++++---- .../Formats/Jpg/JpegDecoderTests.cs | 11 ++++++++++ tests/ImageSharp.Tests/TestImages.cs | 1 + tests/Images/Input/Jpg/issues/Issue2638.jpg | 3 +++ 4 files changed, 31 insertions(+), 4 deletions(-) create mode 100644 tests/Images/Input/Jpg/issues/Issue2638.jpg diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index 0877dbc922..c2b0cb6e07 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -22,6 +22,9 @@ internal struct JpegBitReader // Whether there is no more good data to pull from the stream for the current mcu. private bool badData; + // How many times have we hit the eof. + private int eofHitCount; + public JpegBitReader(BufferedReadStream stream) { this.stream = stream; @@ -31,6 +34,7 @@ internal struct JpegBitReader this.MarkerPosition = 0; this.badData = false; this.NoData = false; + this.eofHitCount = 0; } /// @@ -80,6 +84,9 @@ internal struct JpegBitReader [MethodImpl(InliningOptions.ShortMethod)] public bool HasBadMarker() => this.Marker != JpegConstants.Markers.XFF && !this.HasRestartMarker(); + [MethodImpl(InliningOptions.ShortMethod)] + public bool HasEndMarker() => this.Marker == JpegConstants.Markers.EOI; + [MethodImpl(InliningOptions.AlwaysInline)] public void FillBuffer() { @@ -219,11 +226,16 @@ internal struct JpegBitReader // we know we have hit the EOI and completed decoding the scan buffer. if (value == -1 || (this.badData && this.data == 0 && this.stream.Position >= this.stream.Length)) { - // We've encountered the end of the file stream which means there's no EOI marker + // We've passed the end of the file stream which means there's no EOI marker // in the image or the SOS marker has the wrong dimensions set. - this.badData = true; - this.NoData = true; - value = 0; + if (this.eofHitCount > JpegConstants.Huffman.FetchLoop) + { + this.badData = true; + this.NoData = true; + value = 0; + } + + this.eofHitCount++; } return value; diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index c8d93f6e9e..6a94a98ac6 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -364,4 +364,15 @@ public partial class JpegDecoderTests image.DebugSave(provider); image.CompareToOriginal(provider); } + + // https://github.com/SixLabors/ImageSharp/issues/2638 + [Theory] + [WithFile(TestImages.Jpeg.Issues.Issue2638, PixelTypes.Rgba32)] + public void Issue2638_DecodeWorks(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(JpegDecoder.Instance); + image.DebugSave(provider); + image.CompareToOriginal(provider); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 00f7370f31..fe633fddc3 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -315,6 +315,7 @@ public static class TestImages public const string Issue2564 = "Jpg/issues/issue-2564.jpg"; public const string HangBadScan = "Jpg/issues/Hang_C438A851.jpg"; public const string Issue2517 = "Jpg/issues/issue2517-bad-d7.jpg"; + public const string Issue2638 = "Jpg/issues/Issue2638.jpg"; public static class Fuzz { diff --git a/tests/Images/Input/Jpg/issues/Issue2638.jpg b/tests/Images/Input/Jpg/issues/Issue2638.jpg new file mode 100644 index 0000000000..f42d67b0e8 --- /dev/null +++ b/tests/Images/Input/Jpg/issues/Issue2638.jpg @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:208d5b0b727bbef120a7e090e020a48f99c9e264c2d3939ba749f8620853c1fe +size 70876 From 4f289f9e126d39191f747bd53ae32cb325f01178 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:31:57 +1000 Subject: [PATCH 174/219] Remove unused code. --- .../Formats/Jpeg/Components/Decoder/JpegBitReader.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index c2b0cb6e07..babd2ff4df 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -84,9 +84,6 @@ internal struct JpegBitReader [MethodImpl(InliningOptions.ShortMethod)] public bool HasBadMarker() => this.Marker != JpegConstants.Markers.XFF && !this.HasRestartMarker(); - [MethodImpl(InliningOptions.ShortMethod)] - public bool HasEndMarker() => this.Marker == JpegConstants.Markers.EOI; - [MethodImpl(InliningOptions.AlwaysInline)] public void FillBuffer() { From ea12c0d480510fedda02afeb420d623a8e5901a7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Tue, 19 Mar 2024 00:35:23 +1000 Subject: [PATCH 175/219] Update comment --- src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs index babd2ff4df..e71d86a1d9 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/JpegBitReader.cs @@ -223,7 +223,7 @@ internal struct JpegBitReader // we know we have hit the EOI and completed decoding the scan buffer. if (value == -1 || (this.badData && this.data == 0 && this.stream.Position >= this.stream.Length)) { - // We've passed the end of the file stream which means there's no EOI marker + // We've hit the end of the file stream more times than allowed which means there's no EOI marker // in the image or the SOS marker has the wrong dimensions set. if (this.eofHitCount > JpegConstants.Huffman.FetchLoop) { From 2067026c0933ced15027db458b9d7d641ed7a65c Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Fri, 15 Mar 2024 20:02:00 +1000 Subject: [PATCH 176/219] Ensure VP8X alpha flag is updated correctly. --- .../Formats/Webp/BitWriter/BitWriterBase.cs | 26 +++++++++++++----- .../Formats/Webp/Chunks/WebpVp8X.cs | 23 +++++++++++++++- .../Formats/Webp/Lossless/Vp8LEncoder.cs | 20 +++++++++----- .../Formats/Webp/Lossy/Vp8Encoder.cs | 24 +++++++++++------ src/ImageSharp/Formats/Webp/RiffHelper.cs | 17 +++++++++++- .../Formats/Webp/WebpChunkParsingUtils.cs | 1 - .../Formats/Webp/WebpDecoderCore.cs | 2 +- .../Formats/Webp/WebpEncoderCore.cs | 27 ++++++++++++------- 8 files changed, 105 insertions(+), 35 deletions(-) diff --git a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs index 9279926869..39c4beb618 100644 --- a/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs +++ b/src/ImageSharp/Formats/Webp/BitWriter/BitWriterBase.cs @@ -88,7 +88,8 @@ internal abstract class BitWriterBase /// The color profile. /// Flag indicating, if a alpha channel is present. /// Flag indicating, if an animation parameter is present. - public static void WriteTrunksBeforeData( + /// A or a default instance. + public static WebpVp8X WriteTrunksBeforeData( Stream stream, uint width, uint height, @@ -102,16 +103,19 @@ internal abstract class BitWriterBase RiffHelper.BeginWriteRiffFile(stream, WebpConstants.WebpFourCc); // Write VP8X, header if necessary. + WebpVp8X vp8x = default; bool isVp8X = exifProfile != null || xmpProfile != null || iccProfile != null || hasAlpha || hasAnimation; if (isVp8X) { - WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha, hasAnimation); + vp8x = WriteVp8XHeader(stream, exifProfile, xmpProfile, iccProfile, width, height, hasAlpha, hasAnimation); if (iccProfile != null) { RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Iccp, iccProfile.ToByteArray()); } } + + return vp8x; } /// @@ -124,10 +128,16 @@ internal abstract class BitWriterBase /// Write the trunks after data trunk. /// /// The stream to write to. - /// The exif profile. + /// The VP8X chunk. + /// Whether to update the chunk. + /// The initial position of the stream before encoding. + /// The EXIF profile. /// The XMP profile. public static void WriteTrunksAfterData( Stream stream, + in WebpVp8X vp8x, + bool updateVp8x, + long initialPosition, ExifProfile? exifProfile, XmpProfile? xmpProfile) { @@ -141,7 +151,7 @@ internal abstract class BitWriterBase RiffHelper.WriteChunk(stream, (uint)WebpChunkType.Xmp, xmpProfile.Data); } - RiffHelper.EndWriteRiffFile(stream, 4); + RiffHelper.EndWriteRiffFile(stream, in vp8x, updateVp8x, initialPosition); } /// @@ -186,19 +196,21 @@ internal abstract class BitWriterBase /// Writes a VP8X header to the stream. /// /// The stream to write to. - /// A exif profile or null, if it does not exist. - /// A XMP profile or null, if it does not exist. + /// An EXIF profile or null, if it does not exist. + /// An XMP profile or null, if it does not exist. /// The color profile. /// The width of the image. /// The height of the image. /// Flag indicating, if a alpha channel is present. /// Flag indicating, if an animation parameter is present. - protected static void WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) + protected static WebpVp8X WriteVp8XHeader(Stream stream, ExifProfile? exifProfile, XmpProfile? xmpProfile, IccProfile? iccProfile, uint width, uint height, bool hasAlpha, bool hasAnimation) { WebpVp8X chunk = new(hasAnimation, xmpProfile != null, exifProfile != null, hasAlpha, iccProfile != null, width, height); chunk.Validate(MaxDimension, MaxCanvasPixels); chunk.WriteTo(stream); + + return chunk; } } diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index f781d6114d..f60d0c8374 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -3,7 +3,7 @@ namespace SixLabors.ImageSharp.Formats.Webp.Chunks; -internal readonly struct WebpVp8X +internal readonly struct WebpVp8X : IEquatable { public WebpVp8X(bool hasAnimation, bool hasXmp, bool hasExif, bool hasAlpha, bool hasIcc, uint width, uint height) { @@ -51,6 +51,24 @@ internal readonly struct WebpVp8X /// public uint Height { get; } + public static bool operator ==(WebpVp8X left, WebpVp8X right) => left.Equals(right); + + public static bool operator !=(WebpVp8X left, WebpVp8X right) => !(left == right); + + public override bool Equals(object? obj) => obj is WebpVp8X x && this.Equals(x); + + public bool Equals(WebpVp8X other) + => this.HasAnimation == other.HasAnimation + && this.HasXmp == other.HasXmp + && this.HasExif == other.HasExif + && this.HasAlpha == other.HasAlpha + && this.HasIcc == other.HasIcc + && this.Width == other.Width + && this.Height == other.Height; + + public override int GetHashCode() + => HashCode.Combine(this.HasAnimation, this.HasXmp, this.HasExif, this.HasAlpha, this.HasIcc, this.Width, this.Height); + public void Validate(uint maxDimension, ulong maxCanvasPixels) { if (this.Width > maxDimension || this.Height > maxDimension) @@ -65,6 +83,9 @@ internal readonly struct WebpVp8X } } + public WebpVp8X WithAlpha(bool hasAlpha) + => new(this.HasAnimation, this.HasXmp, this.HasExif, hasAlpha, this.HasIcc, this.Width, this.Height); + public void WriteTo(Stream stream) { byte flags = 0; diff --git a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs index f15cb3eb58..f658e40f6f 100644 --- a/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossless/Vp8LEncoder.cs @@ -236,7 +236,7 @@ internal class Vp8LEncoder : IDisposable /// public Vp8LHashChain HashChain { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAnimation) + public WebpVp8X EncodeHeader(Image image, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bit-writer buffer to the stream. @@ -246,7 +246,8 @@ internal class Vp8LEncoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksBeforeData( + // The alpha flag is updated following encoding. + WebpVp8X vp8x = BitWriterBase.WriteTrunksBeforeData( stream, (uint)image.Width, (uint)image.Height, @@ -261,9 +262,11 @@ internal class Vp8LEncoder : IDisposable WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } + + return vp8x; } - public void EncodeFooter(Image image, Stream stream) + public void EncodeFooter(Image image, in WebpVp8X vp8x, bool hasAlpha, Stream stream, long initialPosition) where TPixel : unmanaged, IPixel { // Write bytes from the bit-writer buffer to the stream. @@ -272,7 +275,9 @@ internal class Vp8LEncoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + bool updateVp8x = hasAlpha && vp8x != default; + WebpVp8X updated = updateVp8x ? vp8x.WithAlpha(true) : vp8x; + BitWriterBase.WriteTrunksAfterData(stream, in updated, updateVp8x, initialPosition, exifProfile, xmpProfile); } /// @@ -284,7 +289,8 @@ internal class Vp8LEncoder : IDisposable /// The frame metadata. /// The to encode the image data to. /// Flag indicating, if an animation parameter is present. - public void Encode(ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, Stream stream, bool hasAnimation) + /// A indicating whether the frame contains an alpha channel. + public bool Encode(ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, Stream stream, bool hasAnimation) where TPixel : unmanaged, IPixel { // Convert image pixels to bgra array. @@ -323,6 +329,8 @@ internal class Vp8LEncoder : IDisposable { RiffHelper.EndWriteChunk(stream, prevPosition); } + + return hasAlpha; } /// @@ -501,7 +509,7 @@ internal class Vp8LEncoder : IDisposable /// The type of the pixels. /// The frame pixel buffer to convert. /// true, if the image is non opaque. - private bool ConvertPixelsToBgra(Buffer2DRegion pixels) + public bool ConvertPixelsToBgra(Buffer2DRegion pixels) where TPixel : unmanaged, IPixel { bool nonOpaque = false; diff --git a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs index 6e9e4f9cd0..40d91ecf1a 100644 --- a/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs +++ b/src/ImageSharp/Formats/Webp/Lossy/Vp8Encoder.cs @@ -310,7 +310,7 @@ internal class Vp8Encoder : IDisposable /// private int MbHeaderLimit { get; } - public void EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation) + public WebpVp8X EncodeHeader(Image image, Stream stream, bool hasAlpha, bool hasAnimation) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -320,7 +320,7 @@ internal class Vp8Encoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksBeforeData( + WebpVp8X vp8x = BitWriterBase.WriteTrunksBeforeData( stream, (uint)image.Width, (uint)image.Height, @@ -335,9 +335,11 @@ internal class Vp8Encoder : IDisposable WebpMetadata webpMetadata = WebpCommonUtils.GetWebpMetadata(image); BitWriterBase.WriteAnimationParameter(stream, webpMetadata.BackgroundColor, webpMetadata.RepeatCount); } + + return vp8x; } - public void EncodeFooter(Image image, Stream stream) + public void EncodeFooter(Image image, in WebpVp8X vp8x, bool hasAlpha, Stream stream, long initialPosition) where TPixel : unmanaged, IPixel { // Write bytes from the bitwriter buffer to the stream. @@ -346,7 +348,9 @@ internal class Vp8Encoder : IDisposable ExifProfile exifProfile = this.skipMetadata ? null : metadata.ExifProfile; XmpProfile xmpProfile = this.skipMetadata ? null : metadata.XmpProfile; - BitWriterBase.WriteTrunksAfterData(stream, exifProfile, xmpProfile); + bool updateVp8x = hasAlpha && vp8x != default; + WebpVp8X updated = updateVp8x ? vp8x.WithAlpha(true) : vp8x; + BitWriterBase.WriteTrunksAfterData(stream, in updated, updateVp8x, initialPosition, exifProfile, xmpProfile); } /// @@ -357,9 +361,10 @@ internal class Vp8Encoder : IDisposable /// The stream to encode the image data to. /// The region of interest within the frame to encode. /// The frame metadata. - public void EncodeAnimation(ImageFrame frame, Stream stream, Rectangle bounds, WebpFrameMetadata frameMetadata) - where TPixel : unmanaged, IPixel => - this.Encode(stream, frame, bounds, frameMetadata, true, null); + /// A indicating whether the frame contains an alpha channel. + public bool EncodeAnimation(ImageFrame frame, Stream stream, Rectangle bounds, WebpFrameMetadata frameMetadata) + where TPixel : unmanaged, IPixel + => this.Encode(stream, frame, bounds, frameMetadata, true, null); /// /// Encodes the static image frame to the specified stream. @@ -384,7 +389,8 @@ internal class Vp8Encoder : IDisposable /// The frame metadata. /// Flag indicating, if an animation parameter is present. /// The image to encode from. - private void Encode(Stream stream, ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, bool hasAnimation, Image image) + /// A indicating whether the frame contains an alpha channel. + private bool Encode(Stream stream, ImageFrame frame, Rectangle bounds, WebpFrameMetadata frameMetadata, bool hasAnimation, Image image) where TPixel : unmanaged, IPixel { int width = bounds.Width; @@ -514,6 +520,8 @@ internal class Vp8Encoder : IDisposable { encodedAlphaData?.Dispose(); } + + return hasAlpha; } /// diff --git a/src/ImageSharp/Formats/Webp/RiffHelper.cs b/src/ImageSharp/Formats/Webp/RiffHelper.cs index d3862ea8b7..b6318c7486 100644 --- a/src/ImageSharp/Formats/Webp/RiffHelper.cs +++ b/src/ImageSharp/Formats/Webp/RiffHelper.cs @@ -3,6 +3,7 @@ using System.Buffers.Binary; using System.Text; +using SixLabors.ImageSharp.Formats.Webp.Chunks; namespace SixLabors.ImageSharp.Formats.Webp; @@ -107,6 +108,7 @@ internal static class RiffHelper position++; } + // Add the size of the encoded file to the Riff header. BinaryPrimitives.WriteUInt32LittleEndian(buffer, dataSize); stream.Position = sizePosition; stream.Write(buffer); @@ -120,5 +122,18 @@ internal static class RiffHelper return sizePosition; } - public static void EndWriteRiffFile(Stream stream, long sizePosition) => EndWriteChunk(stream, sizePosition); + public static void EndWriteRiffFile(Stream stream, in WebpVp8X vp8x, bool updateVp8x, long sizePosition) + { + EndWriteChunk(stream, sizePosition + 4); + + // Write the VP8X chunk if necessary. + if (updateVp8x) + { + long position = stream.Position; + + stream.Position = sizePosition + 12; + vp8x.WriteTo(stream); + stream.Position = position; + } + } } diff --git a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs index 80ffe8a996..07f09d45ea 100644 --- a/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs +++ b/src/ImageSharp/Formats/Webp/WebpChunkParsingUtils.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers.Binary; -using System.Drawing; using SixLabors.ImageSharp.Formats.Webp.BitReader; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.IO; diff --git a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs index 2991f355ff..21f0f4946b 100644 --- a/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpDecoderCore.cs @@ -54,7 +54,7 @@ internal sealed class WebpDecoderCore : IImageDecoderInternals, IDisposable /// /// The flag to decide how to handle the background color in the Animation Chunk. /// - private BackgroundColorHandling backgroundColorHandling; + private readonly BackgroundColorHandling backgroundColorHandling; /// /// Initializes a new instance of the class. diff --git a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs index e37c1d1796..d29759f9a1 100644 --- a/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs +++ b/src/ImageSharp/Formats/Webp/WebpEncoderCore.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using SixLabors.ImageSharp.Formats.Webp.Chunks; using SixLabors.ImageSharp.Formats.Webp.Lossless; using SixLabors.ImageSharp.Formats.Webp.Lossy; using SixLabors.ImageSharp.Memory; @@ -143,12 +144,14 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - encoder.EncodeHeader(image, stream, hasAnimation); + long initialPosition = stream.Position; + bool hasAlpha = false; + WebpVp8X vp8x = encoder.EncodeHeader(image, stream, hasAnimation); // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); - encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); + hasAlpha |= encoder.Encode(previousFrame, previousFrame.Bounds(), frameMetadata, stream, hasAnimation); if (hasAnimation) { @@ -190,14 +193,14 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.nearLossless, this.nearLosslessQuality); - animatedEncoder.Encode(encodingFrame, bounds, frameMetadata, stream, hasAnimation); + hasAlpha |= animatedEncoder.Encode(encodingFrame, bounds, frameMetadata, stream, hasAnimation); previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } } - encoder.EncodeFooter(image, stream); + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } else { @@ -214,17 +217,20 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.spatialNoiseShaping, this.alphaCompression); + long initialPosition = stream.Position; + bool hasAlpha = false; + WebpVp8X vp8x = default; if (image.Frames.Count > 1) { - // TODO: What about alpha here? - encoder.EncodeHeader(image, stream, false, true); + // The alpha flag is updated following encoding. + vp8x = encoder.EncodeHeader(image, stream, false, true); // Encode the first frame. ImageFrame previousFrame = image.Frames.RootFrame; WebpFrameMetadata frameMetadata = WebpCommonUtils.GetWebpFrameMetadata(previousFrame); WebpDisposalMethod previousDisposal = frameMetadata.DisposalMethod; - encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); + hasAlpha |= encoder.EncodeAnimation(previousFrame, stream, previousFrame.Bounds(), frameMetadata); // Encode additional frames // This frame is reused to store de-duplicated pixel buffers. @@ -263,18 +269,19 @@ internal sealed class WebpEncoderCore : IImageEncoderInternals this.spatialNoiseShaping, this.alphaCompression); - animatedEncoder.EncodeAnimation(encodingFrame, stream, bounds, frameMetadata); + hasAlpha |= animatedEncoder.EncodeAnimation(encodingFrame, stream, bounds, frameMetadata); previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } + + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } else { encoder.EncodeStatic(stream, image); + encoder.EncodeFooter(image, in vp8x, hasAlpha, stream, initialPosition); } - - encoder.EncodeFooter(image, stream); } } } From 6733e8d8231f17ceb906f7d971bb7abaa7c01daf Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sun, 17 Mar 2024 11:05:56 +1000 Subject: [PATCH 177/219] Update WebpVp8X.cs --- src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs index f60d0c8374..491f716500 100644 --- a/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs +++ b/src/ImageSharp/Formats/Webp/Chunks/WebpVp8X.cs @@ -66,7 +66,7 @@ internal readonly struct WebpVp8X : IEquatable && this.Width == other.Width && this.Height == other.Height; - public override int GetHashCode() + public override int GetHashCode() => HashCode.Combine(this.HasAnimation, this.HasXmp, this.HasExif, this.HasAlpha, this.HasIcc, this.Width, this.Height); public void Validate(uint maxDimension, ulong maxCanvasPixels) From 92b82779ac8e7a032989533bb9a01ef092186b2e Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 28 Mar 2024 02:36:45 +0100 Subject: [PATCH 178/219] Limit all allocations --- .../Memory/Allocators/MemoryAllocator.cs | 51 ++++++++++++++++--- .../Allocators/MemoryAllocatorOptions.cs | 21 +++++++- .../Allocators/SimpleGcMemoryAllocator.cs | 10 +++- ...iformUnmanagedMemoryPoolMemoryAllocator.cs | 25 ++++----- .../Memory/InvalidMemoryOperationException.cs | 6 +++ 5 files changed, 93 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs index 2bd9cb5eef..194449cfc1 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs @@ -2,6 +2,8 @@ // Licensed under the Six Labors Split License. using System.Buffers; +using System.Diagnostics.CodeAnalysis; +using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory; @@ -10,6 +12,8 @@ namespace SixLabors.ImageSharp.Memory; /// public abstract class MemoryAllocator { + private const int OneGigabyte = 1 << 30; + /// /// Gets the default platform-specific global instance that /// serves as the default value for . @@ -20,6 +24,12 @@ public abstract class MemoryAllocator /// public static MemoryAllocator Default { get; } = Create(); + internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? + 4L * OneGigabyte : + OneGigabyte; + + internal int SingleBufferAllocationLimitBytes { get; private set; } = OneGigabyte; + /// /// Gets the length of the largest contiguous buffer that can be handled by this allocator instance in bytes. /// @@ -30,16 +40,24 @@ public abstract class MemoryAllocator /// Creates a default instance of a optimized for the executing platform. /// /// The . - public static MemoryAllocator Create() => - new UniformUnmanagedMemoryPoolMemoryAllocator(null); + public static MemoryAllocator Create() => Create(default); /// /// Creates the default using the provided options. /// /// The . /// The . - public static MemoryAllocator Create(MemoryAllocatorOptions options) => - new UniformUnmanagedMemoryPoolMemoryAllocator(options.MaximumPoolSizeMegabytes); + public static MemoryAllocator Create(MemoryAllocatorOptions options) + { + UniformUnmanagedMemoryPoolMemoryAllocator allocator = new(options.MaximumPoolSizeMegabytes); + if (options.AllocationLimitMegabytes.HasValue) + { + allocator.MemoryGroupAllocationLimitBytes = options.AllocationLimitMegabytes.Value * 1024 * 1024; + allocator.SingleBufferAllocationLimitBytes = (int)Math.Min(allocator.SingleBufferAllocationLimitBytes, allocator.MemoryGroupAllocationLimitBytes); + } + + return allocator; + } /// /// Allocates an , holding a of length . @@ -69,10 +87,31 @@ public abstract class MemoryAllocator /// The . /// A new . /// Thrown when 'blockAlignment' converted to bytes is greater than the buffer capacity of the allocator. - internal virtual MemoryGroup AllocateGroup( + internal MemoryGroup AllocateGroup( long totalLength, int bufferAlignment, AllocationOptions options = AllocationOptions.None) where T : struct - => MemoryGroup.Allocate(this, totalLength, bufferAlignment, options); + { + long totalLengthInBytes = totalLength * Unsafe.SizeOf(); + if (totalLengthInBytes < 0) + { + ThrowNotRepresentable(); + } + + if (totalLengthInBytes > this.MemoryGroupAllocationLimitBytes) + { + InvalidMemoryOperationException.ThrowAllocationOverLimitException(totalLengthInBytes, this.MemoryGroupAllocationLimitBytes); + } + + return this.AllocateGroupCore(totalLengthInBytes, totalLength, bufferAlignment, options); + + [DoesNotReturn] + static void ThrowNotRepresentable() => + throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable."); + } + + internal virtual MemoryGroup AllocateGroupCore(long totalLengthInElements, long totalLengthInBytes, int bufferAlignment, AllocationOptions options) + where T : struct + => MemoryGroup.Allocate(this, totalLengthInElements, bufferAlignment, options); } diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs index 5a821fd04a..d9ba62c1ef 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. namespace SixLabors.ImageSharp.Memory; @@ -9,6 +9,7 @@ namespace SixLabors.ImageSharp.Memory; public struct MemoryAllocatorOptions { private int? maximumPoolSizeMegabytes; + private int? allocationLimitMegabytes; /// /// Gets or sets a value defining the maximum size of the 's internal memory pool @@ -27,4 +28,22 @@ public struct MemoryAllocatorOptions this.maximumPoolSizeMegabytes = value; } } + + /// + /// Gets or sets a value defining the maximum (discontiguous) buffer size that can be allocated by the allocator in Megabytes. + /// means platform default: 1GB on 32-bit processes, 4GB on 64-bit processes. + /// + public int? AllocationLimitMegabytes + { + get => this.allocationLimitMegabytes; + set + { + if (value.HasValue) + { + Guard.MustBeGreaterThan(value.Value, 0, nameof(this.AllocationLimitMegabytes)); + } + + this.allocationLimitMegabytes = value; + } + } } diff --git a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs index 41730d9678..e604621954 100644 --- a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs @@ -1,7 +1,8 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Buffers; +using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory.Internals; namespace SixLabors.ImageSharp.Memory; @@ -19,6 +20,13 @@ public sealed class SimpleGcMemoryAllocator : MemoryAllocator { Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); + int lengthInBytes = length * Unsafe.SizeOf(); + + if (lengthInBytes > this.SingleBufferAllocationLimitBytes) + { + InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes); + } + return new BasicArrayBuffer(new T[length]); } } diff --git a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs index 0bae193632..585d4717ac 100644 --- a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs @@ -2,6 +2,7 @@ // Licensed under the Six Labors Split License. using System.Buffers; +using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory.Internals; @@ -86,6 +87,11 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); int lengthInBytes = length * Unsafe.SizeOf(); + if (lengthInBytes > this.SingleBufferAllocationLimitBytes) + { + InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes); + } + if (lengthInBytes <= this.sharedArrayPoolThresholdInBytes) { var buffer = new SharedArrayPoolBuffer(length); @@ -111,20 +117,15 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato } /// - internal override MemoryGroup AllocateGroup( - long totalLength, + internal override MemoryGroup AllocateGroupCore( + long totalLengthInElements, + long totalLengthInBytes, int bufferAlignment, AllocationOptions options = AllocationOptions.None) { - long totalLengthInBytes = totalLength * Unsafe.SizeOf(); - if (totalLengthInBytes < 0) - { - throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable."); - } - if (totalLengthInBytes <= this.sharedArrayPoolThresholdInBytes) { - var buffer = new SharedArrayPoolBuffer((int)totalLength); + var buffer = new SharedArrayPoolBuffer((int)totalLengthInElements); return MemoryGroup.CreateContiguous(buffer, options.Has(AllocationOptions.Clean)); } @@ -134,18 +135,18 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato UnmanagedMemoryHandle mem = this.pool.Rent(); if (mem.IsValid) { - UnmanagedBuffer buffer = this.pool.CreateGuardedBuffer(mem, (int)totalLength, options.Has(AllocationOptions.Clean)); + UnmanagedBuffer buffer = this.pool.CreateGuardedBuffer(mem, (int)totalLengthInElements, options.Has(AllocationOptions.Clean)); return MemoryGroup.CreateContiguous(buffer, options.Has(AllocationOptions.Clean)); } } // Attempt to rent the whole group from the pool, allocate a group of unmanaged buffers if the attempt fails: - if (MemoryGroup.TryAllocate(this.pool, totalLength, bufferAlignment, options, out MemoryGroup? poolGroup)) + if (MemoryGroup.TryAllocate(this.pool, totalLengthInElements, bufferAlignment, options, out MemoryGroup? poolGroup)) { return poolGroup; } - return MemoryGroup.Allocate(this.nonPoolAllocator, totalLength, bufferAlignment, options); + return MemoryGroup.Allocate(this.nonPoolAllocator, totalLengthInElements, bufferAlignment, options); } public override void ReleaseRetainedResources() => this.pool.Release(); diff --git a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs index 6a55472236..0dc8106b6b 100644 --- a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs +++ b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs @@ -1,6 +1,8 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Diagnostics.CodeAnalysis; + namespace SixLabors.ImageSharp.Memory; /// @@ -24,4 +26,8 @@ public class InvalidMemoryOperationException : InvalidOperationException public InvalidMemoryOperationException() { } + + [DoesNotReturn] + internal static void ThrowAllocationOverLimitException(long length, long limit) => + throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of length={length} that exceeded the limit {limit}."); } From 7dd3c43a00fffc7c9e70b6ed53e24c936f4b38a8 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Thu, 28 Mar 2024 02:40:52 +0100 Subject: [PATCH 179/219] reduce UnmanagedMemoryHandle.MaxAllocationAttempts --- .../Memory/Allocators/Internals/UnmanagedMemoryHandle.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs index c13fa754e2..6b31cadf4f 100644 --- a/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs +++ b/src/ImageSharp/Memory/Allocators/Internals/UnmanagedMemoryHandle.cs @@ -11,7 +11,7 @@ namespace SixLabors.ImageSharp.Memory.Internals; internal struct UnmanagedMemoryHandle : IEquatable { // Number of allocation re-attempts when detecting OutOfMemoryException. - private const int MaxAllocationAttempts = 1000; + private const int MaxAllocationAttempts = 10; // Track allocations for testing purposes: private static int totalOutstandingHandles; From 5d9e3051cb50c46fca7a3832188c44285e9d8d24 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 12:33:23 -1000 Subject: [PATCH 180/219] Add test --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png | 3 +++ tests/Images/Input/Png/animated/frame-offset.png | 3 +++ 8 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png create mode 100644 tests/Images/Input/Png/animated/frame-offset.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index de99432bce..b6e798c303 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -87,7 +87,8 @@ public partial class PngDecoderTests TestImages.Png.DisposeBackgroundRegion, TestImages.Png.DisposePreviousFirst, TestImages.Png.DisposeBackgroundBeforeRegion, - TestImages.Png.BlendOverMultiple + TestImages.Png.BlendOverMultiple, + TestImages.Png.FrameOffset }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 5da581e52f..1a1a3cd9e6 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -73,6 +73,7 @@ public static class TestImages public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png"; public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; + public const string FrameOffset = "Png/animated/frame-offset.png"; public const string Issue2666 = "Png/issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png new file mode 100644 index 0000000000..b9fa24c930 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84e2353264e3488122f4d488d7c4b198ff5192ad0c662c7fb0a369c957ecc7ea +size 353 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png new file mode 100644 index 0000000000..6f3a27187c --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2916711d3f4d72eb66a5cfc2b40a3318eb4cce5b367658cfc7e3b573fd39cc33 +size 693 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png new file mode 100644 index 0000000000..50911cce57 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f9d5503414ccefa6b66661b1e93c2c3f6e4491f14af006a71153cecf43b52f5 +size 806 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png new file mode 100644 index 0000000000..89d2f95706 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe42b7dc6524d5589ad680650f4bcd181319b40b258b31e0932d6e936818e980 +size 570 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png new file mode 100644 index 0000000000..c3f2b99b8b --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8002ff5b3451b348f285eec15dd7a093c62d11d8b77c3ead9ac89ca6eb29977d +size 669 diff --git a/tests/Images/Input/Png/animated/frame-offset.png b/tests/Images/Input/Png/animated/frame-offset.png new file mode 100644 index 0000000000..4eebb44a3d --- /dev/null +++ b/tests/Images/Input/Png/animated/frame-offset.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c019073841b48b02cb07c779fed8654c6052aee700e7620d07f5d775d97088f +size 2156 From a58ef4bdb70e9421823b3bb4c6d86b28195073c0 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 13:50:40 -1000 Subject: [PATCH 181/219] Fix ProcessInterlacedPaletteScanline not obeying frameControl.XOffset --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index aa937a8e2a..0f530b478e 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -180,8 +180,9 @@ internal static class PngScanlineProcessor ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); + uint offset = pixelOffset + frameControl.XOffset; - for (nuint x = pixelOffset, o = 0; x < frameControl.XMax; x += increment, o++) + for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); Unsafe.Add(ref rowSpanRef, x) = TPixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToPixel()); From ce069bce2501bccf171bd585e8c854a58ac53687 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 17:49:33 -1000 Subject: [PATCH 182/219] Fix frame dispose operation handling --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 25 +++++++++++-------- .../00.png | 4 +-- .../01.png | 4 +-- .../02.png | 4 +-- .../03.png | 4 +-- .../04.png | 4 +-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 6a321a3ba0..23e3033dcc 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -246,8 +246,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals currentFrameControl.Value, cancellationToken); - previousFrame = currentFrame; - previousFrameControl = currentFrameControl; + // if current frame dispose is restore to previous, then from future frame's perspective, it never happened + if (currentFrameControl.Value.DisposeOperation != PngDisposalMethod.RestoreToPrevious) + { + previousFrame = currentFrame; + previousFrameControl = currentFrameControl; + } + break; case PngChunkType.Data: @@ -645,18 +650,18 @@ internal sealed class PngDecoderCore : IImageDecoderInternals out ImageFrame frame) where TPixel : unmanaged, IPixel { - // We create a clone of the previous frame and add it. - // We will overpaint the difference of pixels on the current frame to create a complete image. - // This ensures that we have enough pixel data to process without distortion. #2450 frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. - if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground - || (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) + // if restoring to before first frame, restore to background + if (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious) + { + Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); + pixelRegion.Clear(); + } + else if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground) { Rectangle restoreArea = previousFrameControl.Bounds; - Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea); - Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(interest); + Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); pixelRegion.Clear(); } diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png index b9fa24c930..870ed61a44 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84e2353264e3488122f4d488d7c4b198ff5192ad0c662c7fb0a369c957ecc7ea -size 353 +oid sha256:b85aaf7153e0ca538856a58d7b069bcc13fadc468ea603c85f8782cc691f86c3 +size 387 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png index 6f3a27187c..cab85d9466 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2916711d3f4d72eb66a5cfc2b40a3318eb4cce5b367658cfc7e3b573fd39cc33 -size 693 +oid sha256:fcb83d6893dcfd869b764ff9846c259eaa0caf26cec3f0fc2cbae2c26f2eeaa5 +size 660 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png index 50911cce57..1a2c5adcf0 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f9d5503414ccefa6b66661b1e93c2c3f6e4491f14af006a71153cecf43b52f5 -size 806 +oid sha256:562ec382f6d2af68e66092bf6949f66147d5f608d3c618eea5a7c1ea400737ff +size 768 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png index 89d2f95706..d850459ee8 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe42b7dc6524d5589ad680650f4bcd181319b40b258b31e0932d6e936818e980 -size 570 +oid sha256:d12a7791b960072e32b78bd9aaf456dc99341eea1c66ea05050433d8c082c6ac +size 579 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png index c3f2b99b8b..000b0567de 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8002ff5b3451b348f285eec15dd7a093c62d11d8b77c3ead9ac89ca6eb29977d -size 669 +oid sha256:2db38d7ffcc95c23a5c94a06f10c6cc67406ae581a955c99ede4af97b1a044f8 +size 628 From b29962abca4758eabed06b526520d82ad31d514c Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 18:14:23 -1000 Subject: [PATCH 183/219] Add test for default image not animated --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + .../00.png | 3 +++ .../01.png | 3 +++ tests/Images/Input/Png/animated/default-not-animated.png | 3 +++ 5 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png create mode 100644 tests/Images/Input/Png/animated/default-not-animated.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index b6e798c303..152598ac81 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -88,7 +88,8 @@ public partial class PngDecoderTests TestImages.Png.DisposePreviousFirst, TestImages.Png.DisposeBackgroundBeforeRegion, TestImages.Png.BlendOverMultiple, - TestImages.Png.FrameOffset + TestImages.Png.FrameOffset, + TestImages.Png.DefaultNotAnimated }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 1a1a3cd9e6..5c80422dad 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -74,6 +74,7 @@ public static class TestImages public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; public const string FrameOffset = "Png/animated/frame-offset.png"; + public const string DefaultNotAnimated = "Png/animated/default-not-animated.png"; public const string Issue2666 = "Png/issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png new file mode 100644 index 0000000000..4c5ea8169a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d4716e18655be53630d6d50daebe8c38e0eedb2432c7a73840b55d1473d5944 +size 1050 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png new file mode 100644 index 0000000000..790fe45e4c --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b5a6d3cf1a777f6b719c2a1cf79bffe2251355d75e6c0f7ce7a973b3d033419 +size 1177 diff --git a/tests/Images/Input/Png/animated/default-not-animated.png b/tests/Images/Input/Png/animated/default-not-animated.png new file mode 100644 index 0000000000..1ed72698d5 --- /dev/null +++ b/tests/Images/Input/Png/animated/default-not-animated.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:647d484c8f320b55824b9219270524df3edc434a4793e1627e0ee14af8d6e4f8 +size 1689 From 5cd98723dc5944f7f3fc98e4996832683b8ce88a Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 18:28:03 -1000 Subject: [PATCH 184/219] Fix handling of case where default image isn't animated --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 22 +++++++++++--------- src/ImageSharp/Formats/Png/PngMetadata.cs | 5 +++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 23e3033dcc..222fe8ed34 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -234,8 +234,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals PngThrowHelper.ThrowMissingFrameControl(); } - previousFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); - this.InitializeFrame(previousFrameControl.Value, currentFrameControl.Value, image, previousFrame, out currentFrame); + this.InitializeFrame(previousFrameControl, currentFrameControl.Value, image, previousFrame, out currentFrame); this.currentStream.Position += 4; this.ReadScanlines( @@ -255,7 +254,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; case PngChunkType.Data: - + pngMetadata.DefaultImageAnimated = currentFrameControl != null; currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); if (image is null) { @@ -272,9 +271,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.ReadNextDataChunk, currentFrameControl.Value, cancellationToken); + if (pngMetadata.DefaultImageAnimated) + { + previousFrame = currentFrame; + previousFrameControl = currentFrameControl; + } - previousFrame = currentFrame; - previousFrameControl = currentFrameControl; break; case PngChunkType.Palette: this.palette = chunk.Data.GetSpan().ToArray(); @@ -643,7 +645,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The previous frame. /// The created frame private void InitializeFrame( - FrameControl previousFrameControl, + FrameControl? previousFrameControl, FrameControl currentFrameControl, Image image, ImageFrame? previousFrame, @@ -652,15 +654,15 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // if restoring to before first frame, restore to background - if (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious) + // If restoring to before first frame, restore to background. Same if first frame (previousFrameControl null). + if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) { Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); pixelRegion.Clear(); } - else if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground) + else if (previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToBackground) { - Rectangle restoreArea = previousFrameControl.Bounds; + Rectangle restoreArea = previousFrameControl.Value.Bounds; Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); pixelRegion.Clear(); } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 93ddcf2636..c4ff3bbe24 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -83,6 +83,11 @@ public class PngMetadata : IDeepCloneable /// public uint RepeatCount { get; set; } = 1; + /// + /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence + /// + public bool DefaultImageAnimated { get; set; } + /// public IDeepCloneable DeepClone() => new PngMetadata(this); From c23283508205a37e15baad4b55bd83ea5e790138 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 19:23:35 -1000 Subject: [PATCH 185/219] Fix PngMetadata copy --- src/ImageSharp/Formats/Png/PngMetadata.cs | 3 ++- tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index c4ff3bbe24..766377f7c9 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -29,6 +29,7 @@ public class PngMetadata : IDeepCloneable this.InterlaceMethod = other.InterlaceMethod; this.TransparentColor = other.TransparentColor; this.RepeatCount = other.RepeatCount; + this.DefaultImageAnimated = other.DefaultImageAnimated; if (other.ColorTable?.Length > 0) { @@ -86,7 +87,7 @@ public class PngMetadata : IDeepCloneable /// /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence /// - public bool DefaultImageAnimated { get; set; } + public bool DefaultImageAnimated { get; set; } = true; /// public IDeepCloneable DeepClone() => new PngMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index b3c122a7a8..4f9ba9abee 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -32,7 +32,8 @@ public class PngMetadataTests InterlaceMethod = PngInterlaceMode.Adam7, Gamma = 2, TextData = new List { new PngTextData("name", "value", "foo", "bar") }, - RepeatCount = 123 + RepeatCount = 123, + DefaultImageAnimated = false }; PngMetadata clone = (PngMetadata)meta.DeepClone(); @@ -44,6 +45,7 @@ public class PngMetadataTests Assert.False(meta.TextData.Equals(clone.TextData)); Assert.True(meta.TextData.SequenceEqual(clone.TextData)); Assert.True(meta.RepeatCount == clone.RepeatCount); + Assert.True(meta.DefaultImageAnimated == clone.DefaultImageAnimated); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; From 5cd2d290526942a9f4a60dcc12fc8db03f7aa194 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 20:11:43 -1000 Subject: [PATCH 186/219] Make PngEncoder respect DefaultImageAnimated --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 43 +++++++++++++------ .../Formats/Png/PngEncoderTests.cs | 23 ++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 113fef5957..078935306f 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -167,6 +167,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable ImageFrame? clonedFrame = null; ImageFrame currentFrame = image.Frames.RootFrame; + int currentFrameIndex = 0; bool clearTransparency = this.encoder.TransparentColorMode is PngTransparentColorMode.Clear; if (clearTransparency) @@ -196,28 +197,49 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); + } + + // If the first frame isn't animated, write it as usual and skip it when writing animated frames + if (!pngMetadata.DefaultImageAnimated || image.Frames.Count == 1) + { + FrameControl frameControl = new((uint)this.width, (uint)this.height); + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + currentFrameIndex++; + } - // Write the first frame. + if (image.Frames.Count > 1) + { + // Write the first animated frame. + currentFrame = image.Frames[currentFrameIndex]; PngFrameMetadata frameMetadata = GetPngFrameMetadata(currentFrame); PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); - this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + uint sequenceNumber = 1; + if (pngMetadata.DefaultImageAnimated) + { + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + } + else + { + sequenceNumber += this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, true); + } + + currentFrameIndex++; // Capture the global palette for reuse on subsequent frames. ReadOnlyMemory? previousPalette = quantized?.Palette.ToArray(); // Write following frames. - uint increment = 0; ImageFrame previousFrame = image.Frames.RootFrame; // This frame is reused to store de-duplicated pixel buffers. using ImageFrame encodingFrame = new(image.Configuration, previousFrame.Size()); - for (int i = 1; i < image.Frames.Count; i++) + for (; currentFrameIndex < image.Frames.Count; currentFrameIndex++) { ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; - currentFrame = image.Frames[i]; - ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; + currentFrame = image.Frames[currentFrameIndex]; + ImageFrame? nextFrame = currentFrameIndex < image.Frames.Count - 1 ? image.Frames[currentFrameIndex + 1] : null; frameMetadata = GetPngFrameMetadata(currentFrame); bool blend = frameMetadata.BlendMethod == PngBlendMethod.Over; @@ -238,22 +260,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable } // Each frame control sequence number must be incremented by the number of frame data chunks that follow. - frameControl = this.WriteFrameControlChunk(stream, frameMetadata, bounds, (uint)i + increment); + frameControl = this.WriteFrameControlChunk(stream, frameMetadata, bounds, sequenceNumber); // Dispose of previous quantized frame and reassign. quantized?.Dispose(); quantized = this.CreateQuantizedImageAndUpdateBitDepth(pngMetadata, encodingFrame, bounds, previousPalette); - increment += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true); + sequenceNumber += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true) + 1; previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } } - else - { - FrameControl frameControl = new((uint)this.width, (uint)this.height); - this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); - } this.WriteEndChunk(stream); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index a70fb86df1..e7884dd580 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -587,6 +587,29 @@ public partial class PngEncoderTests } } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + public void Encode_DefaultNotAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + using MemoryStream memStream = new(); + image.Save(memStream, PngEncoder); + memStream.Position = 0; + + image.DebugSave(provider: provider, encoder: PngEncoder, null, false); + + using Image output = Image.Load(memStream); + ImageComparer.Exact.VerifySimilarity(output, image); + + Assert.Equal(2, image.Frames.Count); + Assert.Equal(image.Frames.Count, output.Frames.Count); + + PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); + PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); + Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); + } + [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) From c5ebbfe76e84f904750199e0fa3482ce67111eca Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Fri, 29 Mar 2024 21:34:48 -1000 Subject: [PATCH 187/219] Add more tests --- .../Formats/Png/PngEncoderTests.Chunks.cs | 33 +++++++++++++++++++ .../Formats/Png/PngMetadataTests.cs | 20 +++++++++++ 2 files changed, 53 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 044da21938..2e3390298b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -3,6 +3,7 @@ using System.Buffers.Binary; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -59,6 +60,38 @@ public partial class PngEncoderTests } } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void AcTL_CorrectlyWritten(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata metadata = image.Metadata.GetPngMetadata(); + int correctFrameCount = image.Frames.Count - (metadata.DefaultImageAnimated ? 0 : 1); + using MemoryStream memStream = new(); + image.Save(memStream, PngEncoder); + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + bool foundAcTl = false; + while (bytesSpan.Length > 0 && !foundAcTl) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan[..4]); + PngChunkType type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (type == PngChunkType.AnimationControl) + { + AnimationControl control = AnimationControl.Parse(bytesSpan[8..]); + foundAcTl = true; + Assert.True(control.NumberFrames == correctFrameCount); + Assert.True(control.NumberPlays == metadata.RepeatCount); + } + + bytesSpan = bytesSpan[(4 + 4 + length + 4)..]; + } + + Assert.True(foundAcTl); + } + [Theory] [InlineData(PngChunkType.Gamma)] [InlineData(PngChunkType.Chroma)] diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 4f9ba9abee..8308935d04 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -146,6 +146,26 @@ public class PngMetadataTests VerifyExifDataIsPresent(exif); } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + public void Decode_IdentifiesDefaultFrameNotAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); + Assert.False(meta.DefaultImageAnimated); + } + + [Theory] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void Decode_IdentifiesDefaultFrameAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); + Assert.True(meta.DefaultImageAnimated); + } + [Theory] [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] public void Decode_IgnoresExifData_WhenIgnoreMetadataIsTrue(TestImageProvider provider) From 61b5b0c3a943816ae1146b1a0a6ded4e7a429075 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Fri, 29 Mar 2024 21:35:53 -1000 Subject: [PATCH 188/219] Fix incorrect acTL frame count --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 078935306f..99f721fcf4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -196,7 +196,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { - this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); + this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.DefaultImageAnimated ? 0 : 1)), pngMetadata.RepeatCount); } // If the first frame isn't animated, write it as usual and skip it when writing animated frames From 5cd96d3bf007a7816691f6b9c2c843118d95a884 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:03:25 -0700 Subject: [PATCH 189/219] re-add comment --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 222fe8ed34..77edf2d9ad 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -654,7 +654,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // If restoring to before first frame, restore to background. Same if first frame (previousFrameControl null). + // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. + // So, if restoring to before first frame, clear entire area. Same if first frame (previousFrameControl null). if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) { Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); From 3dec79c9797ad8d97740924a26980d5ae359ab40 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:28:27 -0700 Subject: [PATCH 190/219] Add test for case with frame offsets --- .../Formats/Png/PngEncoderTests.cs | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index e7884dd580..595adbadce 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -448,6 +448,8 @@ public partial class PngEncoderTests [Theory] [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.FrameOffset, PixelTypes.Rgba32)] public void Encode_APng(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -459,15 +461,17 @@ public partial class PngEncoderTests image.DebugSave(provider: provider, encoder: PngEncoder, null, false); using Image output = Image.Load(memStream); - ImageComparer.Exact.VerifySimilarity(output, image); - Assert.Equal(5, image.Frames.Count); + // some loss from original, due to compositing + ImageComparer.TolerantPercentage(0.01f).VerifySimilarity(output, image); + Assert.Equal(image.Frames.Count, output.Frames.Count); PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); Assert.Equal(originalMetadata.RepeatCount, outputMetadata.RepeatCount); + Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); for (int i = 0; i < image.Frames.Count; i++) { @@ -587,29 +591,6 @@ public partial class PngEncoderTests } } - [Theory] - [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] - public void Encode_DefaultNotAnimated(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - using Image image = provider.GetImage(PngDecoder.Instance); - using MemoryStream memStream = new(); - image.Save(memStream, PngEncoder); - memStream.Position = 0; - - image.DebugSave(provider: provider, encoder: PngEncoder, null, false); - - using Image output = Image.Load(memStream); - ImageComparer.Exact.VerifySimilarity(output, image); - - Assert.Equal(2, image.Frames.Count); - Assert.Equal(image.Frames.Count, output.Frames.Count); - - PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); - PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); - Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); - } - [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) From c31db731ad0b1f070aeb28a0640bba5519faf7b4 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:56:21 -0700 Subject: [PATCH 191/219] re-add rest of comment --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 77edf2d9ad..61074a26ed 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -652,6 +652,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals out ImageFrame frame) where TPixel : unmanaged, IPixel { + // We create a clone of the previous frame and add it. + // We will overpaint the difference of pixels on the current frame to create a complete image. + // This ensures that we have enough pixel data to process without distortion. #2450 frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. From 417667a12c5ba1871b3b33d623e2aaa21020e1d9 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 12:33:23 -1000 Subject: [PATCH 192/219] Add test --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png | 3 +++ .../Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png | 3 +++ tests/Images/Input/Png/animated/frame-offset.png | 3 +++ 8 files changed, 21 insertions(+), 1 deletion(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png create mode 100644 tests/Images/Input/Png/animated/frame-offset.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 9b165526eb..336b89376f 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -87,7 +87,8 @@ public partial class PngDecoderTests TestImages.Png.DisposeBackgroundRegion, TestImages.Png.DisposePreviousFirst, TestImages.Png.DisposeBackgroundBeforeRegion, - TestImages.Png.BlendOverMultiple + TestImages.Png.BlendOverMultiple, + TestImages.Png.FrameOffset }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fe633fddc3..7e6ac9e8d8 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -73,6 +73,7 @@ public static class TestImages public const string DisposeBackgroundRegion = "Png/animated/15-dispose-background-region.png"; public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; + public const string FrameOffset = "Png/animated/frame-offset.png"; public const string Issue2666 = "Png/issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png new file mode 100644 index 0000000000..b9fa24c930 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:84e2353264e3488122f4d488d7c4b198ff5192ad0c662c7fb0a369c957ecc7ea +size 353 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png new file mode 100644 index 0000000000..6f3a27187c --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:2916711d3f4d72eb66a5cfc2b40a3318eb4cce5b367658cfc7e3b573fd39cc33 +size 693 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png new file mode 100644 index 0000000000..50911cce57 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:7f9d5503414ccefa6b66661b1e93c2c3f6e4491f14af006a71153cecf43b52f5 +size 806 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png new file mode 100644 index 0000000000..89d2f95706 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:fe42b7dc6524d5589ad680650f4bcd181319b40b258b31e0932d6e936818e980 +size 570 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png new file mode 100644 index 0000000000..c3f2b99b8b --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8002ff5b3451b348f285eec15dd7a093c62d11d8b77c3ead9ac89ca6eb29977d +size 669 diff --git a/tests/Images/Input/Png/animated/frame-offset.png b/tests/Images/Input/Png/animated/frame-offset.png new file mode 100644 index 0000000000..4eebb44a3d --- /dev/null +++ b/tests/Images/Input/Png/animated/frame-offset.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:3c019073841b48b02cb07c779fed8654c6052aee700e7620d07f5d775d97088f +size 2156 From d933db75ed5fff7e3ada9ded4d5562b2982ca260 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 13:50:40 -1000 Subject: [PATCH 193/219] Fix ProcessInterlacedPaletteScanline not obeying frameControl.XOffset --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index f217515e3c..b327ed21ba 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -198,8 +198,9 @@ internal static class PngScanlineProcessor ref byte scanlineSpanRef = ref MemoryMarshal.GetReference(scanlineSpan); ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); + uint offset = pixelOffset + frameControl.XOffset; - for (nuint x = pixelOffset, o = 0; x < frameControl.XMax; x += increment, o++) + for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToRgba32()); From 63b7ecd87e1d6659874123ac7c8e5baefdc3dc53 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 17:49:33 -1000 Subject: [PATCH 194/219] Fix frame dispose operation handling --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 25 +++++++++++-------- .../00.png | 4 +-- .../01.png | 4 +-- .../02.png | 4 +-- .../03.png | 4 +-- .../04.png | 4 +-- 6 files changed, 25 insertions(+), 20 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a96c53c104..caa104c6e9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -240,8 +240,13 @@ internal sealed class PngDecoderCore : IImageDecoderInternals currentFrameControl.Value, cancellationToken); - previousFrame = currentFrame; - previousFrameControl = currentFrameControl; + // if current frame dispose is restore to previous, then from future frame's perspective, it never happened + if (currentFrameControl.Value.DisposeOperation != PngDisposalMethod.RestoreToPrevious) + { + previousFrame = currentFrame; + previousFrameControl = currentFrameControl; + } + break; case PngChunkType.Data: @@ -639,18 +644,18 @@ internal sealed class PngDecoderCore : IImageDecoderInternals out ImageFrame frame) where TPixel : unmanaged, IPixel { - // We create a clone of the previous frame and add it. - // We will overpaint the difference of pixels on the current frame to create a complete image. - // This ensures that we have enough pixel data to process without distortion. #2450 frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. - if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground - || (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) + // if restoring to before first frame, restore to background + if (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious) + { + Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); + pixelRegion.Clear(); + } + else if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground) { Rectangle restoreArea = previousFrameControl.Bounds; - Rectangle interest = Rectangle.Intersect(frame.Bounds(), restoreArea); - Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(interest); + Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); pixelRegion.Clear(); } diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png index b9fa24c930..870ed61a44 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/00.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:84e2353264e3488122f4d488d7c4b198ff5192ad0c662c7fb0a369c957ecc7ea -size 353 +oid sha256:b85aaf7153e0ca538856a58d7b069bcc13fadc468ea603c85f8782cc691f86c3 +size 387 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png index 6f3a27187c..cab85d9466 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/01.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:2916711d3f4d72eb66a5cfc2b40a3318eb4cce5b367658cfc7e3b573fd39cc33 -size 693 +oid sha256:fcb83d6893dcfd869b764ff9846c259eaa0caf26cec3f0fc2cbae2c26f2eeaa5 +size 660 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png index 50911cce57..1a2c5adcf0 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/02.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:7f9d5503414ccefa6b66661b1e93c2c3f6e4491f14af006a71153cecf43b52f5 -size 806 +oid sha256:562ec382f6d2af68e66092bf6949f66147d5f608d3c618eea5a7c1ea400737ff +size 768 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png index 89d2f95706..d850459ee8 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/03.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:fe42b7dc6524d5589ad680650f4bcd181319b40b258b31e0932d6e936818e980 -size 570 +oid sha256:d12a7791b960072e32b78bd9aaf456dc99341eea1c66ea05050433d8c082c6ac +size 579 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png index c3f2b99b8b..000b0567de 100644 --- a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_frame-offset.png/04.png @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:8002ff5b3451b348f285eec15dd7a093c62d11d8b77c3ead9ac89ca6eb29977d -size 669 +oid sha256:2db38d7ffcc95c23a5c94a06f10c6cc67406ae581a955c99ede4af97b1a044f8 +size 628 From d15a2e79a4fbfbaa150e436e6afa938da131f05d Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 18:14:23 -1000 Subject: [PATCH 195/219] Add test for default image not animated --- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 3 ++- tests/ImageSharp.Tests/TestImages.cs | 1 + .../00.png | 3 +++ .../01.png | 3 +++ tests/Images/Input/Png/animated/default-not-animated.png | 3 +++ 5 files changed, 12 insertions(+), 1 deletion(-) create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png create mode 100644 tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png create mode 100644 tests/Images/Input/Png/animated/default-not-animated.png diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 336b89376f..9ff368d4ec 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -88,7 +88,8 @@ public partial class PngDecoderTests TestImages.Png.DisposePreviousFirst, TestImages.Png.DisposeBackgroundBeforeRegion, TestImages.Png.BlendOverMultiple, - TestImages.Png.FrameOffset + TestImages.Png.FrameOffset, + TestImages.Png.DefaultNotAnimated }; [Theory] diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index 7e6ac9e8d8..afb13363d4 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -74,6 +74,7 @@ public static class TestImages public const string DisposePreviousFirst = "Png/animated/12-dispose-prev-first.png"; public const string BlendOverMultiple = "Png/animated/21-blend-over-multiple.png"; public const string FrameOffset = "Png/animated/frame-offset.png"; + public const string DefaultNotAnimated = "Png/animated/default-not-animated.png"; public const string Issue2666 = "Png/issues/Issue_2666.png"; // Filtered test images from http://www.schaik.com/pngsuite/pngsuite_fil_png.html diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png new file mode 100644 index 0000000000..4c5ea8169a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:8d4716e18655be53630d6d50daebe8c38e0eedb2432c7a73840b55d1473d5944 +size 1050 diff --git a/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png new file mode 100644 index 0000000000..790fe45e4c --- /dev/null +++ b/tests/Images/External/ReferenceOutput/PngDecoderTests/Decode_VerifyAllFrames_Rgba32_default-not-animated.png/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9b5a6d3cf1a777f6b719c2a1cf79bffe2251355d75e6c0f7ce7a973b3d033419 +size 1177 diff --git a/tests/Images/Input/Png/animated/default-not-animated.png b/tests/Images/Input/Png/animated/default-not-animated.png new file mode 100644 index 0000000000..1ed72698d5 --- /dev/null +++ b/tests/Images/Input/Png/animated/default-not-animated.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:647d484c8f320b55824b9219270524df3edc434a4793e1627e0ee14af8d6e4f8 +size 1689 From 9b8ef108d41877464418a16451aac87eec37c8bb Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 18:28:03 -1000 Subject: [PATCH 196/219] Fix handling of case where default image isn't animated --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 22 +++++++++++--------- src/ImageSharp/Formats/Png/PngMetadata.cs | 5 +++++ 2 files changed, 17 insertions(+), 10 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index caa104c6e9..3bc2ccf492 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -228,8 +228,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals PngThrowHelper.ThrowMissingFrameControl(); } - previousFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); - this.InitializeFrame(previousFrameControl.Value, currentFrameControl.Value, image, previousFrame, out currentFrame); + this.InitializeFrame(previousFrameControl, currentFrameControl.Value, image, previousFrame, out currentFrame); this.currentStream.Position += 4; this.ReadScanlines( @@ -249,7 +248,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; case PngChunkType.Data: - + pngMetadata.DefaultImageAnimated = currentFrameControl != null; currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); if (image is null) { @@ -266,9 +265,12 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.ReadNextDataChunk, currentFrameControl.Value, cancellationToken); + if (pngMetadata.DefaultImageAnimated) + { + previousFrame = currentFrame; + previousFrameControl = currentFrameControl; + } - previousFrame = currentFrame; - previousFrameControl = currentFrameControl; break; case PngChunkType.Palette: this.palette = chunk.Data.GetSpan().ToArray(); @@ -637,7 +639,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals /// The previous frame. /// The created frame private void InitializeFrame( - FrameControl previousFrameControl, + FrameControl? previousFrameControl, FrameControl currentFrameControl, Image image, ImageFrame? previousFrame, @@ -646,15 +648,15 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // if restoring to before first frame, restore to background - if (previousFrame is null && previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToPrevious) + // If restoring to before first frame, restore to background. Same if first frame (previousFrameControl null). + if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) { Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); pixelRegion.Clear(); } - else if (previousFrameControl.DisposeOperation == PngDisposalMethod.RestoreToBackground) + else if (previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToBackground) { - Rectangle restoreArea = previousFrameControl.Bounds; + Rectangle restoreArea = previousFrameControl.Value.Bounds; Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(restoreArea); pixelRegion.Clear(); } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 93ddcf2636..c4ff3bbe24 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -83,6 +83,11 @@ public class PngMetadata : IDeepCloneable /// public uint RepeatCount { get; set; } = 1; + /// + /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence + /// + public bool DefaultImageAnimated { get; set; } + /// public IDeepCloneable DeepClone() => new PngMetadata(this); From 85fd4311f1caa30bb37c990842f977ed9a1dec81 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 19:23:35 -1000 Subject: [PATCH 197/219] Fix PngMetadata copy --- src/ImageSharp/Formats/Png/PngMetadata.cs | 3 ++- tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs | 4 +++- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index c4ff3bbe24..766377f7c9 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -29,6 +29,7 @@ public class PngMetadata : IDeepCloneable this.InterlaceMethod = other.InterlaceMethod; this.TransparentColor = other.TransparentColor; this.RepeatCount = other.RepeatCount; + this.DefaultImageAnimated = other.DefaultImageAnimated; if (other.ColorTable?.Length > 0) { @@ -86,7 +87,7 @@ public class PngMetadata : IDeepCloneable /// /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence /// - public bool DefaultImageAnimated { get; set; } + public bool DefaultImageAnimated { get; set; } = true; /// public IDeepCloneable DeepClone() => new PngMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index b3c122a7a8..4f9ba9abee 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -32,7 +32,8 @@ public class PngMetadataTests InterlaceMethod = PngInterlaceMode.Adam7, Gamma = 2, TextData = new List { new PngTextData("name", "value", "foo", "bar") }, - RepeatCount = 123 + RepeatCount = 123, + DefaultImageAnimated = false }; PngMetadata clone = (PngMetadata)meta.DeepClone(); @@ -44,6 +45,7 @@ public class PngMetadataTests Assert.False(meta.TextData.Equals(clone.TextData)); Assert.True(meta.TextData.SequenceEqual(clone.TextData)); Assert.True(meta.RepeatCount == clone.RepeatCount); + Assert.True(meta.DefaultImageAnimated == clone.DefaultImageAnimated); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; From addec72467bacd9fc2152549f9ce22e1b6074006 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Thu, 28 Mar 2024 20:11:43 -1000 Subject: [PATCH 198/219] Make PngEncoder respect DefaultImageAnimated --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 43 +++++++++++++------ .../Formats/Png/PngEncoderTests.cs | 23 ++++++++++ 2 files changed, 53 insertions(+), 13 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index ea94270f2f..d1a600737b 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -161,6 +161,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable ImageFrame? clonedFrame = null; ImageFrame currentFrame = image.Frames.RootFrame; + int currentFrameIndex = 0; bool clearTransparency = this.encoder.TransparentColorMode is PngTransparentColorMode.Clear; if (clearTransparency) @@ -190,28 +191,49 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); + } + + // If the first frame isn't animated, write it as usual and skip it when writing animated frames + if (!pngMetadata.DefaultImageAnimated || image.Frames.Count == 1) + { + FrameControl frameControl = new((uint)this.width, (uint)this.height); + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + currentFrameIndex++; + } - // Write the first frame. + if (image.Frames.Count > 1) + { + // Write the first animated frame. + currentFrame = image.Frames[currentFrameIndex]; PngFrameMetadata frameMetadata = GetPngFrameMetadata(currentFrame); PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); - this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + uint sequenceNumber = 1; + if (pngMetadata.DefaultImageAnimated) + { + this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); + } + else + { + sequenceNumber += this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, true); + } + + currentFrameIndex++; // Capture the global palette for reuse on subsequent frames. ReadOnlyMemory? previousPalette = quantized?.Palette.ToArray(); // Write following frames. - uint increment = 0; ImageFrame previousFrame = image.Frames.RootFrame; // This frame is reused to store de-duplicated pixel buffers. using ImageFrame encodingFrame = new(image.Configuration, previousFrame.Size()); - for (int i = 1; i < image.Frames.Count; i++) + for (; currentFrameIndex < image.Frames.Count; currentFrameIndex++) { ImageFrame? prev = previousDisposal == PngDisposalMethod.RestoreToBackground ? null : previousFrame; - currentFrame = image.Frames[i]; - ImageFrame? nextFrame = i < image.Frames.Count - 1 ? image.Frames[i + 1] : null; + currentFrame = image.Frames[currentFrameIndex]; + ImageFrame? nextFrame = currentFrameIndex < image.Frames.Count - 1 ? image.Frames[currentFrameIndex + 1] : null; frameMetadata = GetPngFrameMetadata(currentFrame); bool blend = frameMetadata.BlendMethod == PngBlendMethod.Over; @@ -232,22 +254,17 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable } // Each frame control sequence number must be incremented by the number of frame data chunks that follow. - frameControl = this.WriteFrameControlChunk(stream, frameMetadata, bounds, (uint)i + increment); + frameControl = this.WriteFrameControlChunk(stream, frameMetadata, bounds, sequenceNumber); // Dispose of previous quantized frame and reassign. quantized?.Dispose(); quantized = this.CreateQuantizedImageAndUpdateBitDepth(pngMetadata, encodingFrame, bounds, previousPalette); - increment += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true); + sequenceNumber += this.WriteDataChunks(frameControl, encodingFrame.PixelBuffer.GetRegion(bounds), quantized, stream, true) + 1; previousFrame = currentFrame; previousDisposal = frameMetadata.DisposalMethod; } } - else - { - FrameControl frameControl = new((uint)this.width, (uint)this.height); - this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); - } this.WriteEndChunk(stream); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 950f1d2e3a..bbd7ff4e49 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -586,6 +586,29 @@ public partial class PngEncoderTests } } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + public void Encode_DefaultNotAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + using MemoryStream memStream = new(); + image.Save(memStream, PngEncoder); + memStream.Position = 0; + + image.DebugSave(provider: provider, encoder: PngEncoder, null, false); + + using Image output = Image.Load(memStream); + ImageComparer.Exact.VerifySimilarity(output, image); + + Assert.Equal(2, image.Frames.Count); + Assert.Equal(image.Frames.Count, output.Frames.Count); + + PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); + PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); + Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); + } + [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) From 9ae8be4c8afc28f6c648f913b558ba23e6a8e191 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Fri, 29 Mar 2024 21:34:48 -1000 Subject: [PATCH 199/219] Add more tests --- .../Formats/Png/PngEncoderTests.Chunks.cs | 33 +++++++++++++++++++ .../Formats/Png/PngMetadataTests.cs | 20 +++++++++++ 2 files changed, 53 insertions(+) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 044da21938..2e3390298b 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -3,6 +3,7 @@ using System.Buffers.Binary; using SixLabors.ImageSharp.Formats.Png; +using SixLabors.ImageSharp.Formats.Png.Chunks; using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming @@ -59,6 +60,38 @@ public partial class PngEncoderTests } } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void AcTL_CorrectlyWritten(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata metadata = image.Metadata.GetPngMetadata(); + int correctFrameCount = image.Frames.Count - (metadata.DefaultImageAnimated ? 0 : 1); + using MemoryStream memStream = new(); + image.Save(memStream, PngEncoder); + memStream.Position = 0; + Span bytesSpan = memStream.ToArray().AsSpan(8); // Skip header. + bool foundAcTl = false; + while (bytesSpan.Length > 0 && !foundAcTl) + { + int length = BinaryPrimitives.ReadInt32BigEndian(bytesSpan[..4]); + PngChunkType type = (PngChunkType)BinaryPrimitives.ReadInt32BigEndian(bytesSpan.Slice(4, 4)); + if (type == PngChunkType.AnimationControl) + { + AnimationControl control = AnimationControl.Parse(bytesSpan[8..]); + foundAcTl = true; + Assert.True(control.NumberFrames == correctFrameCount); + Assert.True(control.NumberPlays == metadata.RepeatCount); + } + + bytesSpan = bytesSpan[(4 + 4 + length + 4)..]; + } + + Assert.True(foundAcTl); + } + [Theory] [InlineData(PngChunkType.Gamma)] [InlineData(PngChunkType.Chroma)] diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 4f9ba9abee..8308935d04 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -146,6 +146,26 @@ public class PngMetadataTests VerifyExifDataIsPresent(exif); } + [Theory] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + public void Decode_IdentifiesDefaultFrameNotAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); + Assert.False(meta.DefaultImageAnimated); + } + + [Theory] + [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + public void Decode_IdentifiesDefaultFrameAnimated(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(PngDecoder.Instance); + PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); + Assert.True(meta.DefaultImageAnimated); + } + [Theory] [WithFile(TestImages.Png.PngWithMetadata, PixelTypes.Rgba32)] public void Decode_IgnoresExifData_WhenIgnoreMetadataIsTrue(TestImageProvider provider) From ceb7dc0e7e26ee289cb8e2743ceb5b6793f65c41 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Fri, 29 Mar 2024 21:35:53 -1000 Subject: [PATCH 200/219] Fix incorrect acTL frame count --- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index d1a600737b..e0f7ed9489 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -190,7 +190,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { - this.WriteAnimationControlChunk(stream, (uint)image.Frames.Count, pngMetadata.RepeatCount); + this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.DefaultImageAnimated ? 0 : 1)), pngMetadata.RepeatCount); } // If the first frame isn't animated, write it as usual and skip it when writing animated frames From 4698e8ca3b4a6a453a45cace6554f40148c53d3e Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:03:25 -0700 Subject: [PATCH 201/219] re-add comment --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 3bc2ccf492..dd2ce9eb14 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -648,7 +648,8 @@ internal sealed class PngDecoderCore : IImageDecoderInternals { frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); - // If restoring to before first frame, restore to background. Same if first frame (previousFrameControl null). + // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. + // So, if restoring to before first frame, clear entire area. Same if first frame (previousFrameControl null). if (previousFrameControl == null || (previousFrame is null && previousFrameControl.Value.DisposeOperation == PngDisposalMethod.RestoreToPrevious)) { Buffer2DRegion pixelRegion = frame.PixelBuffer.GetRegion(); From b1a5593b20e89786343d5d7d71a2c08dd606b1e9 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:28:27 -0700 Subject: [PATCH 202/219] Add test for case with frame offsets --- .../Formats/Png/PngEncoderTests.cs | 31 ++++--------------- 1 file changed, 6 insertions(+), 25 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index bbd7ff4e49..6c4047be8e 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -447,6 +447,8 @@ public partial class PngEncoderTests [Theory] [WithFile(TestImages.Png.APng, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] + [WithFile(TestImages.Png.FrameOffset, PixelTypes.Rgba32)] public void Encode_APng(TestImageProvider provider) where TPixel : unmanaged, IPixel { @@ -458,15 +460,17 @@ public partial class PngEncoderTests image.DebugSave(provider: provider, encoder: PngEncoder, null, false); using Image output = Image.Load(memStream); - ImageComparer.Exact.VerifySimilarity(output, image); - Assert.Equal(5, image.Frames.Count); + // some loss from original, due to compositing + ImageComparer.TolerantPercentage(0.01f).VerifySimilarity(output, image); + Assert.Equal(image.Frames.Count, output.Frames.Count); PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); Assert.Equal(originalMetadata.RepeatCount, outputMetadata.RepeatCount); + Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); for (int i = 0; i < image.Frames.Count; i++) { @@ -586,29 +590,6 @@ public partial class PngEncoderTests } } - [Theory] - [WithFile(TestImages.Png.DefaultNotAnimated, PixelTypes.Rgba32)] - public void Encode_DefaultNotAnimated(TestImageProvider provider) - where TPixel : unmanaged, IPixel - { - using Image image = provider.GetImage(PngDecoder.Instance); - using MemoryStream memStream = new(); - image.Save(memStream, PngEncoder); - memStream.Position = 0; - - image.DebugSave(provider: provider, encoder: PngEncoder, null, false); - - using Image output = Image.Load(memStream); - ImageComparer.Exact.VerifySimilarity(output, image); - - Assert.Equal(2, image.Frames.Count); - Assert.Equal(image.Frames.Count, output.Frames.Count); - - PngMetadata originalMetadata = image.Metadata.GetPngMetadata(); - PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); - Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); - } - [Theory] [MemberData(nameof(PngTrnsFiles))] public void Encode_PreserveTrns(string imagePath, PngBitDepth pngBitDepth, PngColorType pngColorType) From 848013921281a7381ea4328f4f3d37f3587b01bf Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Mon, 1 Apr 2024 17:56:21 -0700 Subject: [PATCH 203/219] re-add rest of comment --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index dd2ce9eb14..1afb65566d 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -646,6 +646,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals out ImageFrame frame) where TPixel : unmanaged, IPixel { + // We create a clone of the previous frame and add it. + // We will overpaint the difference of pixels on the current frame to create a complete image. + // This ensures that we have enough pixel data to process without distortion. #2450 frame = image.Frames.AddFrame(previousFrame ?? image.Frames.RootFrame); // If the first `fcTL` chunk uses a `dispose_op` of APNG_DISPOSE_OP_PREVIOUS it should be treated as APNG_DISPOSE_OP_BACKGROUND. From 63d4b2028a370debe463077fb7fa7fe8469676f7 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Wed, 3 Apr 2024 15:24:05 +1000 Subject: [PATCH 204/219] Fix args and add tests --- .../ComponentProcessors/ComponentProcessor.cs | 2 +- .../Components/Encoder/ComponentProcessor.cs | 2 +- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 3 ++ src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 2 +- .../Memory/Allocators/MemoryAllocator.cs | 21 +++++--------- .../Allocators/MemoryAllocatorOptions.cs | 4 +-- .../Allocators/SimpleGcMemoryAllocator.cs | 10 ++++--- ...iformUnmanagedMemoryPoolMemoryAllocator.cs | 14 +++++---- .../DiscontiguousBuffers/MemoryGroup{T}.cs | 13 +++++---- .../Memory/InvalidMemoryOperationException.cs | 11 ++++++- .../Memory/MemoryAllocatorExtensions.cs | 14 ++++----- .../Transforms/Resize/ResizeKernelMap.cs | 2 +- .../Transforms/Resize/ResizeWorker.cs | 2 +- .../Formats/Bmp/BmpDecoderTests.cs | 9 ++++++ .../Formats/Jpg/JpegDecoderTests.cs | 18 +++--------- .../SimpleGcMemoryAllocatorTests.cs | 16 ++++++---- ...niformUnmanagedPoolMemoryAllocatorTests.cs | 13 ++++++++- .../ImageSharp.Tests/Memory/Buffer2DTests.cs | 29 +++++++++++++++++-- .../MemoryGroupTests.Allocate.cs | 12 ++++++-- tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Bmp/issue-2696.bmp | 3 ++ 21 files changed, 131 insertions(+), 71 deletions(-) create mode 100644 tests/Images/Input/Bmp/issue-2696.bmp diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs index f0cc4d5e82..3bdaf2dc27 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs @@ -16,7 +16,7 @@ internal abstract class ComponentProcessor : IDisposable this.Component = component; this.BlockAreaSize = component.SubSamplingDivisors * blockSize; - this.ColorBuffer = memoryAllocator.Allocate2DOveraligned( + this.ColorBuffer = memoryAllocator.Allocate2DOverAligned( postProcessorBufferSize.Width, postProcessorBufferSize.Height, this.BlockAreaSize.Height); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs index c33a8a1968..9346b11e7b 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs @@ -28,7 +28,7 @@ internal class ComponentProcessor : IDisposable this.blockAreaSize = component.SubSamplingDivisors * 8; // alignment of 8 so each block stride can be sampled from a single 'ref pointer' - this.ColorBuffer = memoryAllocator.Allocate2DOveraligned( + this.ColorBuffer = memoryAllocator.Allocate2DOverAligned( postProcessorBufferSize.Width, postProcessorBufferSize.Height, 8, diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index a96c53c104..abd5cadeb1 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -1968,6 +1968,9 @@ internal sealed class PngDecoderCore : IImageDecoderInternals } // We rent the buffer here to return it afterwards in Decode() + // We don't want to throw a degenerated memory exception here as we want to allow partial decoding + // so limit the length. + length = (int)Math.Min(length, this.currentStream.Length - this.currentStream.Position); IMemoryOwner buffer = this.configuration.MemoryAllocator.Allocate(length, AllocationOptions.Clean); this.currentStream.Read(buffer.GetSpan(), 0, length); diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 26e057bff9..34f4c2bcf1 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -84,7 +84,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals throw new UnknownImageFormatException("Width or height cannot be 0"); } - Image image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); + Image image = new(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.fileHeader.ColorMapType == 1) diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs index 194449cfc1..b56bedd045 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; namespace SixLabors.ImageSharp.Memory; @@ -24,9 +23,7 @@ public abstract class MemoryAllocator /// public static MemoryAllocator Default { get; } = Create(); - internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? - 4L * OneGigabyte : - OneGigabyte; + internal long MemoryGroupAllocationLimitBytes { get; private set; } = Environment.Is64BitProcess ? 4L * OneGigabyte : OneGigabyte; internal int SingleBufferAllocationLimitBytes { get; private set; } = OneGigabyte; @@ -82,6 +79,7 @@ public abstract class MemoryAllocator /// /// Allocates a . /// + /// The type of element to allocate. /// The total length of the buffer. /// The expected alignment (eg. to make sure image rows fit into single buffers). /// The . @@ -93,22 +91,19 @@ public abstract class MemoryAllocator AllocationOptions options = AllocationOptions.None) where T : struct { - long totalLengthInBytes = totalLength * Unsafe.SizeOf(); - if (totalLengthInBytes < 0) + if (totalLength < 0) { - ThrowNotRepresentable(); + InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLength); } - if (totalLengthInBytes > this.MemoryGroupAllocationLimitBytes) + ulong totalLengthInBytes = (ulong)totalLength * (ulong)Unsafe.SizeOf(); + if (totalLengthInBytes > (ulong)this.MemoryGroupAllocationLimitBytes) { InvalidMemoryOperationException.ThrowAllocationOverLimitException(totalLengthInBytes, this.MemoryGroupAllocationLimitBytes); } - return this.AllocateGroupCore(totalLengthInBytes, totalLength, bufferAlignment, options); - - [DoesNotReturn] - static void ThrowNotRepresentable() => - throw new InvalidMemoryOperationException("Attempted to allocate a MemoryGroup of a size that is not representable."); + // Cast to long is safe because we already checked that the total length is within the limit. + return this.AllocateGroupCore(totalLength, (long)totalLengthInBytes, bufferAlignment, options); } internal virtual MemoryGroup AllocateGroupCore(long totalLengthInElements, long totalLengthInBytes, int bufferAlignment, AllocationOptions options) diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs index d9ba62c1ef..9f25816609 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs @@ -17,7 +17,7 @@ public struct MemoryAllocatorOptions /// public int? MaximumPoolSizeMegabytes { - get => this.maximumPoolSizeMegabytes; + readonly get => this.maximumPoolSizeMegabytes; set { if (value.HasValue) @@ -35,7 +35,7 @@ public struct MemoryAllocatorOptions /// public int? AllocationLimitMegabytes { - get => this.allocationLimitMegabytes; + readonly get => this.allocationLimitMegabytes; set { if (value.HasValue) diff --git a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs index e604621954..675afe8b9f 100644 --- a/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/SimpleGcMemoryAllocator.cs @@ -18,11 +18,13 @@ public sealed class SimpleGcMemoryAllocator : MemoryAllocator /// public override IMemoryOwner Allocate(int length, AllocationOptions options = AllocationOptions.None) { - Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); - - int lengthInBytes = length * Unsafe.SizeOf(); + if (length < 0) + { + InvalidMemoryOperationException.ThrowNegativeAllocationException(length); + } - if (lengthInBytes > this.SingleBufferAllocationLimitBytes) + ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf(); + if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes) { InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes); } diff --git a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs index 585d4717ac..621073a3db 100644 --- a/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/UniformUnmanagedMemoryPoolMemoryAllocator.cs @@ -2,7 +2,6 @@ // Licensed under the Six Labors Split License. using System.Buffers; -using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Memory.Internals; @@ -84,15 +83,18 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato int length, AllocationOptions options = AllocationOptions.None) { - Guard.MustBeGreaterThanOrEqualTo(length, 0, nameof(length)); - int lengthInBytes = length * Unsafe.SizeOf(); + if (length < 0) + { + InvalidMemoryOperationException.ThrowNegativeAllocationException(length); + } - if (lengthInBytes > this.SingleBufferAllocationLimitBytes) + ulong lengthInBytes = (ulong)length * (ulong)Unsafe.SizeOf(); + if (lengthInBytes > (ulong)this.SingleBufferAllocationLimitBytes) { InvalidMemoryOperationException.ThrowAllocationOverLimitException(lengthInBytes, this.SingleBufferAllocationLimitBytes); } - if (lengthInBytes <= this.sharedArrayPoolThresholdInBytes) + if (lengthInBytes <= (ulong)this.sharedArrayPoolThresholdInBytes) { var buffer = new SharedArrayPoolBuffer(length); if (options.Has(AllocationOptions.Clean)) @@ -103,7 +105,7 @@ internal sealed class UniformUnmanagedMemoryPoolMemoryAllocator : MemoryAllocato return buffer; } - if (lengthInBytes <= this.poolBufferSizeInBytes) + if (lengthInBytes <= (ulong)this.poolBufferSizeInBytes) { UnmanagedMemoryHandle mem = this.pool.Rent(); if (mem.IsValid) diff --git a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs index 9695c7f98f..03c29a7231 100644 --- a/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs +++ b/src/ImageSharp/Memory/DiscontiguousBuffers/MemoryGroup{T}.cs @@ -83,15 +83,16 @@ internal abstract partial class MemoryGroup : IMemoryGroup, IDisposable { int bufferCapacityInBytes = allocator.GetBufferCapacityInBytes(); Guard.NotNull(allocator, nameof(allocator)); - Guard.MustBeGreaterThanOrEqualTo(totalLengthInElements, 0, nameof(totalLengthInElements)); - Guard.MustBeGreaterThanOrEqualTo(bufferAlignmentInElements, 0, nameof(bufferAlignmentInElements)); - int blockCapacityInElements = bufferCapacityInBytes / ElementSize; + if (totalLengthInElements < 0) + { + InvalidMemoryOperationException.ThrowNegativeAllocationException(totalLengthInElements); + } - if (bufferAlignmentInElements > blockCapacityInElements) + int blockCapacityInElements = bufferCapacityInBytes / ElementSize; + if (bufferAlignmentInElements < 0 || bufferAlignmentInElements > blockCapacityInElements) { - throw new InvalidMemoryOperationException( - $"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {bufferAlignmentInElements}."); + InvalidMemoryOperationException.ThrowInvalidAlignmentException(bufferAlignmentInElements); } if (totalLengthInElements == 0) diff --git a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs index 0dc8106b6b..81210f13db 100644 --- a/src/ImageSharp/Memory/InvalidMemoryOperationException.cs +++ b/src/ImageSharp/Memory/InvalidMemoryOperationException.cs @@ -28,6 +28,15 @@ public class InvalidMemoryOperationException : InvalidOperationException } [DoesNotReturn] - internal static void ThrowAllocationOverLimitException(long length, long limit) => + internal static void ThrowNegativeAllocationException(long length) => + throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of negative length={length}."); + + [DoesNotReturn] + internal static void ThrowInvalidAlignmentException(long alignment) => + throw new InvalidMemoryOperationException( + $"The buffer capacity of the provided MemoryAllocator is insufficient for the requested buffer alignment: {alignment}."); + + [DoesNotReturn] + internal static void ThrowAllocationOverLimitException(ulong length, long limit) => throw new InvalidMemoryOperationException($"Attempted to allocate a buffer of length={length} that exceeded the limit {limit}."); } diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index ff306e1e45..e0dc8aab36 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -18,20 +18,20 @@ public static class MemoryAllocatorExtensions /// The memory allocator. /// The buffer width. /// The buffer height. - /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . + /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . /// The allocation options. /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, int width, int height, - bool preferContiguosImageBuffers, + bool preferContiguousImageBuffers, AllocationOptions options = AllocationOptions.None) where T : struct { long groupLength = (long)width * height; MemoryGroup memoryGroup; - if (preferContiguosImageBuffers && groupLength < int.MaxValue) + if (preferContiguousImageBuffers && groupLength < int.MaxValue) { IMemoryOwner buffer = memoryAllocator.Allocate((int)groupLength, options); memoryGroup = MemoryGroup.CreateContiguous(buffer, false); @@ -69,16 +69,16 @@ public static class MemoryAllocatorExtensions /// The type of buffer items to allocate. /// The memory allocator. /// The buffer size. - /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . + /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . /// The allocation options. /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, Size size, - bool preferContiguosImageBuffers, + bool preferContiguousImageBuffers, AllocationOptions options = AllocationOptions.None) where T : struct => - Allocate2D(memoryAllocator, size.Width, size.Height, preferContiguosImageBuffers, options); + Allocate2D(memoryAllocator, size.Width, size.Height, preferContiguousImageBuffers, options); /// /// Allocates a buffer of value type objects interpreted as a 2D region @@ -96,7 +96,7 @@ public static class MemoryAllocatorExtensions where T : struct => Allocate2D(memoryAllocator, size.Width, size.Height, false, options); - internal static Buffer2D Allocate2DOveraligned( + internal static Buffer2D Allocate2DOverAligned( this MemoryAllocator memoryAllocator, int width, int height, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index c1907bb520..da26cbefcd 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -50,7 +50,7 @@ internal partial class ResizeKernelMap : IDisposable this.sourceLength = sourceLength; this.DestinationLength = destinationLength; this.MaxDiameter = (radius * 2) + 1; - this.data = memoryAllocator.Allocate2D(this.MaxDiameter, bufferHeight, preferContiguosImageBuffers: true, AllocationOptions.Clean); + this.data = memoryAllocator.Allocate2D(this.MaxDiameter, bufferHeight, preferContiguousImageBuffers: true, AllocationOptions.Clean); this.pinHandle = this.data.DangerousGetSingleMemory().Pin(); this.kernels = new ResizeKernel[destinationLength]; this.tempValues = new double[this.MaxDiameter]; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index cce27a401c..fd13d7b5a6 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -83,7 +83,7 @@ internal sealed class ResizeWorker : IDisposable this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D( this.workerHeight, targetWorkingRect.Width, - preferContiguosImageBuffers: true, + preferContiguousImageBuffers: true, options: AllocationOptions.Clean); this.tempRowBuffer = configuration.MemoryAllocator.Allocate(this.sourceRectangle.Width); diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index e76f21d0e9..be2fa4b685 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -558,4 +558,13 @@ public class BmpDecoderTests // Compare to reference output instead. image.CompareToReferenceOutput(provider, extension: "png"); } + + [Theory] + [WithFile(Issue2696, PixelTypes.Rgba32)] + public void BmpDecoder_ThrowsException_Issue2696(TestImageProvider provider) + where TPixel : unmanaged, IPixel + => Assert.Throws(() => + { + using Image image = provider.GetImage(BmpDecoder.Instance); + }); } diff --git a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs index 6a94a98ac6..2fe4282607 100644 --- a/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Jpg/JpegDecoderTests.cs @@ -338,21 +338,11 @@ public partial class JpegDecoderTests } [Theory] - [WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.L8)] - public void DecodeHang(TestImageProvider provider) + [WithFile(TestImages.Jpeg.Issues.HangBadScan, PixelTypes.Rgb24)] + public void DecodeHang_ThrowsException(TestImageProvider provider) where TPixel : unmanaged, IPixel - { - if (TestEnvironment.IsWindows && - TestEnvironment.RunsOnCI) - { - // Windows CI runs consistently fail with OOM. - return; - } - - using Image image = provider.GetImage(JpegDecoder.Instance); - Assert.Equal(65503, image.Width); - Assert.Equal(65503, image.Height); - } + => Assert.Throws( + () => { using Image image = provider.GetImage(JpegDecoder.Instance); }); // https://github.com/SixLabors/ImageSharp/issues/2517 [Theory] diff --git a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs index 780ba7f20e..665f34a342 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/SimpleGcMemoryAllocatorTests.cs @@ -19,13 +19,17 @@ public class SimpleGcMemoryAllocatorTests protected SimpleGcMemoryAllocator MemoryAllocator { get; } = new SimpleGcMemoryAllocator(); - [Theory] - [InlineData(-1)] - public void Allocate_IncorrectAmount_ThrowsCorrect_ArgumentOutOfRangeException(int length) + public static TheoryData InvalidLengths { get; set; } = new() { - ArgumentOutOfRangeException ex = Assert.Throws(() => this.MemoryAllocator.Allocate(length)); - Assert.Equal("length", ex.ParamName); - } + { -1 }, + { (1 << 30) + 1 } + }; + + [Theory] + [MemberData(nameof(InvalidLengths))] + public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(int length) + => Assert.Throws( + () => this.MemoryAllocator.Allocate(length)); [Fact] public unsafe void Allocate_MemoryIsPinnableMultipleTimes() diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 7e7c136635..6187b536ed 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -111,9 +111,20 @@ public class UniformUnmanagedPoolMemoryAllocatorTests public void AllocateGroup_SizeInBytesOverLongMaxValue_ThrowsInvalidMemoryOperationException() { var allocator = new UniformUnmanagedMemoryPoolMemoryAllocator(null); - Assert.Throws(() => allocator.AllocateGroup(int.MaxValue * (long)int.MaxValue, int.MaxValue)); + Assert.Throws(() => allocator.AllocateGroup(int.MaxValue * (long)int.MaxValue, int.MaxValue)); } + public static TheoryData InvalidLengths { get; set; } = new() + { + { -1 }, + { (1 << 30) + 1 } + }; + + [Theory] + [MemberData(nameof(InvalidLengths))] + public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(int length) + => Assert.Throws(() => new UniformUnmanagedMemoryPoolMemoryAllocator(null).Allocate(length)); + [Fact] public unsafe void Allocate_MemoryIsPinnableMultipleTimes() { diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 5364de0652..3ef4fc540c 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -4,6 +4,7 @@ using System.Runtime.CompilerServices; using System.Runtime.InteropServices; using SixLabors.ImageSharp.Memory; +using SixLabors.ImageSharp.PixelFormats; // ReSharper disable InconsistentNaming namespace SixLabors.ImageSharp.Tests.Memory; @@ -72,11 +73,11 @@ public partial class Buffer2DTests using Buffer2D buffer = useSizeOverload ? this.MemoryAllocator.Allocate2D( new Size(200, 200), - preferContiguosImageBuffers: true) : + preferContiguousImageBuffers: true) : this.MemoryAllocator.Allocate2D( 200, 200, - preferContiguosImageBuffers: true); + preferContiguousImageBuffers: true); Assert.Equal(1, buffer.FastMemoryGroup.Count); Assert.Equal(200 * 200, buffer.FastMemoryGroup.TotalLength); } @@ -87,7 +88,7 @@ public partial class Buffer2DTests { this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; - using Buffer2D buffer = this.MemoryAllocator.Allocate2DOveraligned(width, height, alignmentMultiplier); + using Buffer2D buffer = this.MemoryAllocator.Allocate2DOverAligned(width, height, alignmentMultiplier); MemoryGroup memoryGroup = buffer.FastMemoryGroup; int expectedAlignment = width * alignmentMultiplier; @@ -337,4 +338,26 @@ public partial class Buffer2DTests Assert.False(mgBefore.IsValid); Assert.NotSame(mgBefore, buffer1.MemoryGroup); } + + public static TheoryData InvalidLengths { get; set; } = new() + { + { new(-1, -1) }, + { new(32768, 32769) }, + { new(32769, 32768) } + }; + + [Theory] + [MemberData(nameof(InvalidLengths))] + public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException(Size size) + => Assert.Throws(() => this.MemoryAllocator.Allocate2D(size.Width, size.Height)); + + [Theory] + [MemberData(nameof(InvalidLengths))] + public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException_Size(Size size) + => Assert.Throws(() => this.MemoryAllocator.Allocate2D(new Size(size))); + + [Theory] + [MemberData(nameof(InvalidLengths))] + public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException_OverAligned(Size size) + => Assert.Throws(() => this.MemoryAllocator.Allocate2DOverAligned(size.Width, size.Height, 1)); } diff --git a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs index 936e482cb3..4c7de5412c 100644 --- a/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs +++ b/tests/ImageSharp.Tests/Memory/DiscontiguousBuffers/MemoryGroupTests.Allocate.cs @@ -1,4 +1,4 @@ -// Copyright (c) Six Labors. +// Copyright (c) Six Labors. // Licensed under the Six Labors Split License. using System.Runtime.CompilerServices; @@ -219,11 +219,17 @@ public partial class MemoryGroupTests [StructLayout(LayoutKind.Sequential, Size = 5)] internal struct S5 { - public override string ToString() => "S5"; + public override readonly string ToString() => nameof(S5); } [StructLayout(LayoutKind.Sequential, Size = 4)] internal struct S4 { - public override string ToString() => "S4"; + public override readonly string ToString() => nameof(S4); +} + +[StructLayout(LayoutKind.Explicit, Size = 512)] +internal struct S512 +{ + public override readonly string ToString() => nameof(S512); } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index fe633fddc3..42778e6f11 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -439,6 +439,8 @@ public static class TestImages public const string Rgba321010102 = "Bmp/rgba32-1010102.bmp"; public const string RgbaAlphaBitfields = "Bmp/rgba32abf.bmp"; + public const string Issue2696 = "Bmp/issue-2696.bmp"; + public const string BlackWhitePalletDataMatrix = "Bmp/bit1datamatrix.bmp"; public static readonly string[] BitFields = diff --git a/tests/Images/Input/Bmp/issue-2696.bmp b/tests/Images/Input/Bmp/issue-2696.bmp new file mode 100644 index 0000000000..4a42e456cb --- /dev/null +++ b/tests/Images/Input/Bmp/issue-2696.bmp @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:de7e7ec0454a55f6a76c859f356b240a3d4cb56ca50dfa209a1813dd09e12076 +size 143 From 94d7f3c479ed2ecf7e831f19da1bdac67b6d7398 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Tue, 2 Apr 2024 23:00:15 -0700 Subject: [PATCH 205/219] Rename DefaultImageAnimated to AnimateRootFrame --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 ++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 +++--- src/ImageSharp/Formats/Png/PngMetadata.cs | 6 +++--- .../Formats/Png/PngEncoderTests.Chunks.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 61074a26ed..9cf88f729d 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -254,7 +254,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; case PngChunkType.Data: - pngMetadata.DefaultImageAnimated = currentFrameControl != null; + pngMetadata.AnimateRootFrame = currentFrameControl != null; currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); if (image is null) { @@ -271,7 +271,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.ReadNextDataChunk, currentFrameControl.Value, cancellationToken); - if (pngMetadata.DefaultImageAnimated) + if (pngMetadata.AnimateRootFrame) { previousFrame = currentFrame; previousFrameControl = currentFrameControl; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index 99f721fcf4..6e8224f01e 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -196,11 +196,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { - this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.DefaultImageAnimated ? 0 : 1)), pngMetadata.RepeatCount); + this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.AnimateRootFrame ? 0 : 1)), pngMetadata.RepeatCount); } // If the first frame isn't animated, write it as usual and skip it when writing animated frames - if (!pngMetadata.DefaultImageAnimated || image.Frames.Count == 1) + if (!pngMetadata.AnimateRootFrame || image.Frames.Count == 1) { FrameControl frameControl = new((uint)this.width, (uint)this.height); this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); @@ -215,7 +215,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); uint sequenceNumber = 1; - if (pngMetadata.DefaultImageAnimated) + if (pngMetadata.AnimateRootFrame) { this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 766377f7c9..d9028dd807 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -29,7 +29,7 @@ public class PngMetadata : IDeepCloneable this.InterlaceMethod = other.InterlaceMethod; this.TransparentColor = other.TransparentColor; this.RepeatCount = other.RepeatCount; - this.DefaultImageAnimated = other.DefaultImageAnimated; + this.AnimateRootFrame = other.AnimateRootFrame; if (other.ColorTable?.Length > 0) { @@ -85,9 +85,9 @@ public class PngMetadata : IDeepCloneable public uint RepeatCount { get; set; } = 1; /// - /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence + /// Gets or sets a value indicating whether the root frame is shown as part of the animated sequence /// - public bool DefaultImageAnimated { get; set; } = true; + public bool AnimateRootFrame { get; set; } = true; /// public IDeepCloneable DeepClone() => new PngMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 2e3390298b..76fd260dd5 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -68,7 +68,7 @@ public partial class PngEncoderTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata metadata = image.Metadata.GetPngMetadata(); - int correctFrameCount = image.Frames.Count - (metadata.DefaultImageAnimated ? 0 : 1); + int correctFrameCount = image.Frames.Count - (metadata.AnimateRootFrame ? 0 : 1); using MemoryStream memStream = new(); image.Save(memStream, PngEncoder); memStream.Position = 0; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 595adbadce..35c446c704 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -471,7 +471,7 @@ public partial class PngEncoderTests PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); Assert.Equal(originalMetadata.RepeatCount, outputMetadata.RepeatCount); - Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); + Assert.Equal(originalMetadata.AnimateRootFrame, outputMetadata.AnimateRootFrame); for (int i = 0; i < image.Frames.Count; i++) { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 8308935d04..225e4deef2 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -33,7 +33,7 @@ public class PngMetadataTests Gamma = 2, TextData = new List { new PngTextData("name", "value", "foo", "bar") }, RepeatCount = 123, - DefaultImageAnimated = false + AnimateRootFrame = false }; PngMetadata clone = (PngMetadata)meta.DeepClone(); @@ -45,7 +45,7 @@ public class PngMetadataTests Assert.False(meta.TextData.Equals(clone.TextData)); Assert.True(meta.TextData.SequenceEqual(clone.TextData)); Assert.True(meta.RepeatCount == clone.RepeatCount); - Assert.True(meta.DefaultImageAnimated == clone.DefaultImageAnimated); + Assert.True(meta.AnimateRootFrame == clone.AnimateRootFrame); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; @@ -153,7 +153,7 @@ public class PngMetadataTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.False(meta.DefaultImageAnimated); + Assert.False(meta.AnimateRootFrame); } [Theory] @@ -163,7 +163,7 @@ public class PngMetadataTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.True(meta.DefaultImageAnimated); + Assert.True(meta.AnimateRootFrame); } [Theory] From c8eab788dd8d496703ba7c82bd595fe2fea81d83 Mon Sep 17 00:00:00 2001 From: SpaceCheetah Date: Tue, 2 Apr 2024 23:00:15 -0700 Subject: [PATCH 206/219] Rename DefaultImageAnimated to AnimateRootFrame --- src/ImageSharp/Formats/Png/PngDecoderCore.cs | 4 ++-- src/ImageSharp/Formats/Png/PngEncoderCore.cs | 6 +++--- src/ImageSharp/Formats/Png/PngMetadata.cs | 6 +++--- .../Formats/Png/PngEncoderTests.Chunks.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs | 2 +- tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs | 8 ++++---- 6 files changed, 14 insertions(+), 14 deletions(-) diff --git a/src/ImageSharp/Formats/Png/PngDecoderCore.cs b/src/ImageSharp/Formats/Png/PngDecoderCore.cs index 1afb65566d..c4b10b4dc9 100644 --- a/src/ImageSharp/Formats/Png/PngDecoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngDecoderCore.cs @@ -248,7 +248,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals break; case PngChunkType.Data: - pngMetadata.DefaultImageAnimated = currentFrameControl != null; + pngMetadata.AnimateRootFrame = currentFrameControl != null; currentFrameControl ??= new((uint)this.header.Width, (uint)this.header.Height); if (image is null) { @@ -265,7 +265,7 @@ internal sealed class PngDecoderCore : IImageDecoderInternals this.ReadNextDataChunk, currentFrameControl.Value, cancellationToken); - if (pngMetadata.DefaultImageAnimated) + if (pngMetadata.AnimateRootFrame) { previousFrame = currentFrame; previousFrameControl = currentFrameControl; diff --git a/src/ImageSharp/Formats/Png/PngEncoderCore.cs b/src/ImageSharp/Formats/Png/PngEncoderCore.cs index e0f7ed9489..802e4dd6a4 100644 --- a/src/ImageSharp/Formats/Png/PngEncoderCore.cs +++ b/src/ImageSharp/Formats/Png/PngEncoderCore.cs @@ -190,11 +190,11 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable if (image.Frames.Count > 1) { - this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.DefaultImageAnimated ? 0 : 1)), pngMetadata.RepeatCount); + this.WriteAnimationControlChunk(stream, (uint)(image.Frames.Count - (pngMetadata.AnimateRootFrame ? 0 : 1)), pngMetadata.RepeatCount); } // If the first frame isn't animated, write it as usual and skip it when writing animated frames - if (!pngMetadata.DefaultImageAnimated || image.Frames.Count == 1) + if (!pngMetadata.AnimateRootFrame || image.Frames.Count == 1) { FrameControl frameControl = new((uint)this.width, (uint)this.height); this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); @@ -209,7 +209,7 @@ internal sealed class PngEncoderCore : IImageEncoderInternals, IDisposable PngDisposalMethod previousDisposal = frameMetadata.DisposalMethod; FrameControl frameControl = this.WriteFrameControlChunk(stream, frameMetadata, currentFrame.Bounds(), 0); uint sequenceNumber = 1; - if (pngMetadata.DefaultImageAnimated) + if (pngMetadata.AnimateRootFrame) { this.WriteDataChunks(frameControl, currentFrame.PixelBuffer.GetRegion(), quantized, stream, false); } diff --git a/src/ImageSharp/Formats/Png/PngMetadata.cs b/src/ImageSharp/Formats/Png/PngMetadata.cs index 766377f7c9..d9028dd807 100644 --- a/src/ImageSharp/Formats/Png/PngMetadata.cs +++ b/src/ImageSharp/Formats/Png/PngMetadata.cs @@ -29,7 +29,7 @@ public class PngMetadata : IDeepCloneable this.InterlaceMethod = other.InterlaceMethod; this.TransparentColor = other.TransparentColor; this.RepeatCount = other.RepeatCount; - this.DefaultImageAnimated = other.DefaultImageAnimated; + this.AnimateRootFrame = other.AnimateRootFrame; if (other.ColorTable?.Length > 0) { @@ -85,9 +85,9 @@ public class PngMetadata : IDeepCloneable public uint RepeatCount { get; set; } = 1; /// - /// Gets or sets a value indicating whether the default image is shown as part of the animated sequence + /// Gets or sets a value indicating whether the root frame is shown as part of the animated sequence /// - public bool DefaultImageAnimated { get; set; } = true; + public bool AnimateRootFrame { get; set; } = true; /// public IDeepCloneable DeepClone() => new PngMetadata(this); diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs index 2e3390298b..76fd260dd5 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.Chunks.cs @@ -68,7 +68,7 @@ public partial class PngEncoderTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata metadata = image.Metadata.GetPngMetadata(); - int correctFrameCount = image.Frames.Count - (metadata.DefaultImageAnimated ? 0 : 1); + int correctFrameCount = image.Frames.Count - (metadata.AnimateRootFrame ? 0 : 1); using MemoryStream memStream = new(); image.Save(memStream, PngEncoder); memStream.Position = 0; diff --git a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs index 6c4047be8e..ca5aae961c 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngEncoderTests.cs @@ -470,7 +470,7 @@ public partial class PngEncoderTests PngMetadata outputMetadata = output.Metadata.GetPngMetadata(); Assert.Equal(originalMetadata.RepeatCount, outputMetadata.RepeatCount); - Assert.Equal(originalMetadata.DefaultImageAnimated, outputMetadata.DefaultImageAnimated); + Assert.Equal(originalMetadata.AnimateRootFrame, outputMetadata.AnimateRootFrame); for (int i = 0; i < image.Frames.Count; i++) { diff --git a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs index 8308935d04..225e4deef2 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngMetadataTests.cs @@ -33,7 +33,7 @@ public class PngMetadataTests Gamma = 2, TextData = new List { new PngTextData("name", "value", "foo", "bar") }, RepeatCount = 123, - DefaultImageAnimated = false + AnimateRootFrame = false }; PngMetadata clone = (PngMetadata)meta.DeepClone(); @@ -45,7 +45,7 @@ public class PngMetadataTests Assert.False(meta.TextData.Equals(clone.TextData)); Assert.True(meta.TextData.SequenceEqual(clone.TextData)); Assert.True(meta.RepeatCount == clone.RepeatCount); - Assert.True(meta.DefaultImageAnimated == clone.DefaultImageAnimated); + Assert.True(meta.AnimateRootFrame == clone.AnimateRootFrame); clone.BitDepth = PngBitDepth.Bit2; clone.ColorType = PngColorType.Palette; @@ -153,7 +153,7 @@ public class PngMetadataTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.False(meta.DefaultImageAnimated); + Assert.False(meta.AnimateRootFrame); } [Theory] @@ -163,7 +163,7 @@ public class PngMetadataTests { using Image image = provider.GetImage(PngDecoder.Instance); PngMetadata meta = image.Metadata.GetFormatMetadata(PngFormat.Instance); - Assert.True(meta.DefaultImageAnimated); + Assert.True(meta.AnimateRootFrame); } [Theory] From da497882fed5080ef78fd65364e14d34be6b9a22 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Apr 2024 09:18:23 +1000 Subject: [PATCH 207/219] Revert additional changes --- .../ComponentProcessors/ComponentProcessor.cs | 2 +- .../Jpeg/Components/Encoder/ComponentProcessor.cs | 2 +- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 2 +- .../Memory/Allocators/MemoryAllocatorOptions.cs | 4 ++-- src/ImageSharp/Memory/MemoryAllocatorExtensions.cs | 14 +++++++------- .../Transforms/Resize/ResizeKernelMap.cs | 2 +- .../Processors/Transforms/Resize/ResizeWorker.cs | 2 +- tests/ImageSharp.Tests/Memory/Buffer2DTests.cs | 8 ++++---- 8 files changed, 18 insertions(+), 18 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs index 3bdaf2dc27..f0cc4d5e82 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/ComponentProcessors/ComponentProcessor.cs @@ -16,7 +16,7 @@ internal abstract class ComponentProcessor : IDisposable this.Component = component; this.BlockAreaSize = component.SubSamplingDivisors * blockSize; - this.ColorBuffer = memoryAllocator.Allocate2DOverAligned( + this.ColorBuffer = memoryAllocator.Allocate2DOveraligned( postProcessorBufferSize.Width, postProcessorBufferSize.Height, this.BlockAreaSize.Height); diff --git a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs index 9346b11e7b..c33a8a1968 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Encoder/ComponentProcessor.cs @@ -28,7 +28,7 @@ internal class ComponentProcessor : IDisposable this.blockAreaSize = component.SubSamplingDivisors * 8; // alignment of 8 so each block stride can be sampled from a single 'ref pointer' - this.ColorBuffer = memoryAllocator.Allocate2DOverAligned( + this.ColorBuffer = memoryAllocator.Allocate2DOveraligned( postProcessorBufferSize.Width, postProcessorBufferSize.Height, 8, diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 34f4c2bcf1..26e057bff9 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -84,7 +84,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals throw new UnknownImageFormatException("Width or height cannot be 0"); } - Image image = new(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); + Image image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.fileHeader.ColorMapType == 1) diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs index 9f25816609..d9ba62c1ef 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocatorOptions.cs @@ -17,7 +17,7 @@ public struct MemoryAllocatorOptions /// public int? MaximumPoolSizeMegabytes { - readonly get => this.maximumPoolSizeMegabytes; + get => this.maximumPoolSizeMegabytes; set { if (value.HasValue) @@ -35,7 +35,7 @@ public struct MemoryAllocatorOptions /// public int? AllocationLimitMegabytes { - readonly get => this.allocationLimitMegabytes; + get => this.allocationLimitMegabytes; set { if (value.HasValue) diff --git a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs index e0dc8aab36..ff306e1e45 100644 --- a/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs +++ b/src/ImageSharp/Memory/MemoryAllocatorExtensions.cs @@ -18,20 +18,20 @@ public static class MemoryAllocatorExtensions /// The memory allocator. /// The buffer width. /// The buffer height. - /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . + /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . /// The allocation options. /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, int width, int height, - bool preferContiguousImageBuffers, + bool preferContiguosImageBuffers, AllocationOptions options = AllocationOptions.None) where T : struct { long groupLength = (long)width * height; MemoryGroup memoryGroup; - if (preferContiguousImageBuffers && groupLength < int.MaxValue) + if (preferContiguosImageBuffers && groupLength < int.MaxValue) { IMemoryOwner buffer = memoryAllocator.Allocate((int)groupLength, options); memoryGroup = MemoryGroup.CreateContiguous(buffer, false); @@ -69,16 +69,16 @@ public static class MemoryAllocatorExtensions /// The type of buffer items to allocate. /// The memory allocator. /// The buffer size. - /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . + /// A value indicating whether the allocated buffer should be contiguous, unless bigger than . /// The allocation options. /// The . public static Buffer2D Allocate2D( this MemoryAllocator memoryAllocator, Size size, - bool preferContiguousImageBuffers, + bool preferContiguosImageBuffers, AllocationOptions options = AllocationOptions.None) where T : struct => - Allocate2D(memoryAllocator, size.Width, size.Height, preferContiguousImageBuffers, options); + Allocate2D(memoryAllocator, size.Width, size.Height, preferContiguosImageBuffers, options); /// /// Allocates a buffer of value type objects interpreted as a 2D region @@ -96,7 +96,7 @@ public static class MemoryAllocatorExtensions where T : struct => Allocate2D(memoryAllocator, size.Width, size.Height, false, options); - internal static Buffer2D Allocate2DOverAligned( + internal static Buffer2D Allocate2DOveraligned( this MemoryAllocator memoryAllocator, int width, int height, diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs index da26cbefcd..c1907bb520 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeKernelMap.cs @@ -50,7 +50,7 @@ internal partial class ResizeKernelMap : IDisposable this.sourceLength = sourceLength; this.DestinationLength = destinationLength; this.MaxDiameter = (radius * 2) + 1; - this.data = memoryAllocator.Allocate2D(this.MaxDiameter, bufferHeight, preferContiguousImageBuffers: true, AllocationOptions.Clean); + this.data = memoryAllocator.Allocate2D(this.MaxDiameter, bufferHeight, preferContiguosImageBuffers: true, AllocationOptions.Clean); this.pinHandle = this.data.DangerousGetSingleMemory().Pin(); this.kernels = new ResizeKernel[destinationLength]; this.tempValues = new double[this.MaxDiameter]; diff --git a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs index fd13d7b5a6..cce27a401c 100644 --- a/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs +++ b/src/ImageSharp/Processing/Processors/Transforms/Resize/ResizeWorker.cs @@ -83,7 +83,7 @@ internal sealed class ResizeWorker : IDisposable this.transposedFirstPassBuffer = configuration.MemoryAllocator.Allocate2D( this.workerHeight, targetWorkingRect.Width, - preferContiguousImageBuffers: true, + preferContiguosImageBuffers: true, options: AllocationOptions.Clean); this.tempRowBuffer = configuration.MemoryAllocator.Allocate(this.sourceRectangle.Width); diff --git a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs index 3ef4fc540c..8ba3bf70a2 100644 --- a/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs +++ b/tests/ImageSharp.Tests/Memory/Buffer2DTests.cs @@ -73,11 +73,11 @@ public partial class Buffer2DTests using Buffer2D buffer = useSizeOverload ? this.MemoryAllocator.Allocate2D( new Size(200, 200), - preferContiguousImageBuffers: true) : + preferContiguosImageBuffers: true) : this.MemoryAllocator.Allocate2D( 200, 200, - preferContiguousImageBuffers: true); + preferContiguosImageBuffers: true); Assert.Equal(1, buffer.FastMemoryGroup.Count); Assert.Equal(200 * 200, buffer.FastMemoryGroup.TotalLength); } @@ -88,7 +88,7 @@ public partial class Buffer2DTests { this.MemoryAllocator.BufferCapacityInBytes = sizeof(int) * bufferCapacity; - using Buffer2D buffer = this.MemoryAllocator.Allocate2DOverAligned(width, height, alignmentMultiplier); + using Buffer2D buffer = this.MemoryAllocator.Allocate2DOveraligned(width, height, alignmentMultiplier); MemoryGroup memoryGroup = buffer.FastMemoryGroup; int expectedAlignment = width * alignmentMultiplier; @@ -359,5 +359,5 @@ public partial class Buffer2DTests [Theory] [MemberData(nameof(InvalidLengths))] public void Allocate_IncorrectAmount_ThrowsCorrect_InvalidMemoryOperationException_OverAligned(Size size) - => Assert.Throws(() => this.MemoryAllocator.Allocate2DOverAligned(size.Width, size.Height, 1)); + => Assert.Throws(() => this.MemoryAllocator.Allocate2DOveraligned(size.Width, size.Height, 1)); } From 26d44ef5f127c9869454e6c648bdea248d26a4ac Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Apr 2024 11:29:51 +1000 Subject: [PATCH 208/219] Clear pixel buffers on decode. --- .../Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs | 3 ++- src/ImageSharp/Formats/Tga/TgaDecoderCore.cs | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs index 5add4c6f06..7f89baba58 100644 --- a/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs +++ b/src/ImageSharp/Formats/Jpeg/Components/Decoder/SpectralConverter{TPixel}.cs @@ -201,7 +201,8 @@ internal class SpectralConverter : SpectralConverter, IDisposable this.pixelBuffer = allocator.Allocate2D( pixelSize.Width, pixelSize.Height, - this.Configuration.PreferContiguousImageBuffers); + this.Configuration.PreferContiguousImageBuffers, + AllocationOptions.Clean); this.paddedProxyPixelRow = allocator.Allocate(pixelSize.Width + 3); // Component processors from spectral to RGB diff --git a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs index 26e057bff9..34f4c2bcf1 100644 --- a/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs +++ b/src/ImageSharp/Formats/Tga/TgaDecoderCore.cs @@ -84,7 +84,7 @@ internal sealed class TgaDecoderCore : IImageDecoderInternals throw new UnknownImageFormatException("Width or height cannot be 0"); } - Image image = Image.CreateUninitialized(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); + Image image = new(this.configuration, this.fileHeader.Width, this.fileHeader.Height, this.metadata); Buffer2D pixels = image.GetRootFramePixelBuffer(); if (this.fileHeader.ColorMapType == 1) From fb64b3367fa7e2c68213c94606a9c96037991850 Mon Sep 17 00:00:00 2001 From: James Jackson-South Date: Sat, 6 Apr 2024 12:44:45 +1000 Subject: [PATCH 209/219] Clamp read palette indices. --- src/ImageSharp/Formats/Png/PngScanlineProcessor.cs | 3 ++- tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs | 8 ++++++++ tests/ImageSharp.Tests/TestImages.cs | 2 ++ tests/Images/Input/Png/issues/Issue_2714.png | 3 +++ 4 files changed, 15 insertions(+), 1 deletion(-) create mode 100644 tests/Images/Input/Png/issues/Issue_2714.png diff --git a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs index b327ed21ba..c653e71c62 100644 --- a/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs +++ b/src/ImageSharp/Formats/Png/PngScanlineProcessor.cs @@ -199,11 +199,12 @@ internal static class PngScanlineProcessor ref TPixel rowSpanRef = ref MemoryMarshal.GetReference(rowSpan); ref Color paletteBase = ref MemoryMarshal.GetReference(palette.Value.Span); uint offset = pixelOffset + frameControl.XOffset; + int maxIndex = palette.Value.Length - 1; for (nuint x = offset, o = 0; x < frameControl.XMax; x += increment, o++) { uint index = Unsafe.Add(ref scanlineSpanRef, o); - pixel.FromRgba32(Unsafe.Add(ref paletteBase, index).ToRgba32()); + pixel.FromRgba32(Unsafe.Add(ref paletteBase, (int)Math.Min(index, maxIndex)).ToRgba32()); Unsafe.Add(ref rowSpanRef, x) = pixel; } } diff --git a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs index 9ff368d4ec..8d4bc3f461 100644 --- a/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Png/PngDecoderTests.cs @@ -693,4 +693,12 @@ public partial class PngDecoderTests string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, file)); _ = Image.Identify(path); } + + [Theory] + [InlineData(TestImages.Png.Bad.Issue2714BadPalette)] + public void Decode_BadPalette(string file) + { + string path = Path.GetFullPath(Path.Combine(TestEnvironment.InputImagesDirectoryFullPath, file)); + using Image image = Image.Load(path); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index afb13363d4..f925f1a90b 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -192,6 +192,8 @@ public static class TestImages public const string BadZTXT = "Png/issues/bad-ztxt.png"; public const string BadZTXT2 = "Png/issues/bad-ztxt2.png"; + + public const string Issue2714BadPalette = "Png/issues/Issue_2714.png"; } } diff --git a/tests/Images/Input/Png/issues/Issue_2714.png b/tests/Images/Input/Png/issues/Issue_2714.png new file mode 100644 index 0000000000..9bb231dd9f --- /dev/null +++ b/tests/Images/Input/Png/issues/Issue_2714.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:9a4b6efc3090dbd70ae9efe97ea817464845263536beea4e80fd7c884dee6c5a +size 128 From d1cc651e19def81df66779985a50f9372db332bc Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Apr 2024 23:18:45 +0200 Subject: [PATCH 210/219] fix BmpDecoder_ThrowsException_Issue2696 --- tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs | 11 +++++++---- tests/Images/Input/Bmp/issue-2696.bmp | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs index be2fa4b685..1ce794e44b 100644 --- a/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Bmp/BmpDecoderTests.cs @@ -563,8 +563,11 @@ public class BmpDecoderTests [WithFile(Issue2696, PixelTypes.Rgba32)] public void BmpDecoder_ThrowsException_Issue2696(TestImageProvider provider) where TPixel : unmanaged, IPixel - => Assert.Throws(() => - { - using Image image = provider.GetImage(BmpDecoder.Instance); - }); + { + InvalidImageContentException ex = Assert.Throws(() => + { + using Image image = provider.GetImage(BmpDecoder.Instance); + }); + Assert.IsType(ex.InnerException); + } } diff --git a/tests/Images/Input/Bmp/issue-2696.bmp b/tests/Images/Input/Bmp/issue-2696.bmp index 4a42e456cb..6770dd9469 100644 --- a/tests/Images/Input/Bmp/issue-2696.bmp +++ b/tests/Images/Input/Bmp/issue-2696.bmp @@ -1,3 +1,3 @@ version https://git-lfs.github.com/spec/v1 -oid sha256:de7e7ec0454a55f6a76c859f356b240a3d4cb56ca50dfa209a1813dd09e12076 -size 143 +oid sha256:bc42cda9bac8fc73351ad03bf55214069bb8d31ea5bdd806321a8cc8b56c282e +size 126 From 572366e07806bfb6a269c9a132c9afbd2a9191d0 Mon Sep 17 00:00:00 2001 From: antonfirsov Date: Wed, 10 Apr 2024 23:33:34 +0200 Subject: [PATCH 211/219] test allocation limits --- ...niformUnmanagedPoolMemoryAllocatorTests.cs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 6187b536ed..077d0afed8 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -418,4 +418,28 @@ public class UniformUnmanagedPoolMemoryAllocatorTests _ = MemoryAllocator.Create(); } } + + [Fact] + public void Allocate_OverLimit_ThrowsInvalidMemoryOperationException() + { + MemoryAllocator allocator = MemoryAllocator.Create(new MemoryAllocatorOptions() + { + AllocationLimitMegabytes = 4 + }); + const int oneMb = 1 << 20; + allocator.Allocate(4 * oneMb).Dispose(); // Should work + Assert.Throws(() => allocator.Allocate(5 * oneMb)); + } + + [Fact] + public void AllocateGroup_OverLimit_ThrowsInvalidMemoryOperationException() + { + MemoryAllocator allocator = MemoryAllocator.Create(new MemoryAllocatorOptions() + { + AllocationLimitMegabytes = 4 + }); + const int oneMb = 1 << 20; + allocator.AllocateGroup(4 * oneMb, 1024).Dispose(); // Should work + Assert.Throws(() => allocator.AllocateGroup(5 * oneMb, 1024)); + } } From 9c5a393650bc40928caa89765501fdaf7bea1484 Mon Sep 17 00:00:00 2001 From: Dan Kroymann Date: Mon, 22 Apr 2024 17:29:20 -0700 Subject: [PATCH 212/219] Fix another async-over-sync issue where DecodeAsync() would internally block on a synchronous stream read when detecting the image format --- src/ImageSharp/Image.Decode.cs | 89 +++++++++++++++++++++++++++++----- 1 file changed, 78 insertions(+), 11 deletions(-) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 887cb23ca4..8eec3c55f0 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -1,6 +1,7 @@ // Copyright (c) Six Labors. // Licensed under the Six Labors Split License. +using System.Buffers; using SixLabors.ImageSharp.Formats; using SixLabors.ImageSharp.Memory; using SixLabors.ImageSharp.Metadata; @@ -67,20 +68,70 @@ public abstract partial class Image int i; do { - i = stream.Read(headersBuffer, n, headerSize - n); + i = stream.Read(headersBuffer[n..headerSize]); n += i; } while (n < headerSize && i > 0); stream.Position = startPosition; + return InternalDetectFormat(configuration, headersBuffer[..n]); + } + + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The general configuration. + /// The image stream to read the header from. + /// The token to monitor for cancellation requests. + /// The mime type or null if none found. + /// The input format is not recognized. + private static async ValueTask InternalDetectFormatAsync( + Configuration configuration, + Stream stream, + CancellationToken cancellationToken) + { + // We take a minimum of the stream length vs the max header size and always check below + // to ensure that only formats that headers fit within the given buffer length are tested. + int headerSize = (int)Math.Min(configuration.MaxHeaderSize, stream.Length); + if (headerSize <= 0) + { + ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager); + } + + using (IMemoryOwner memoryOwner = MemoryPool.Shared.Rent(headerSize)) + { + Memory headersBuffer = memoryOwner.Memory; + long startPosition = stream.Position; + + // Read doesn't always guarantee the full returned length so read a byte + // at a time until we get either our count or hit the end of the stream. + int n = 0; + int i; + do + { + i = await stream.ReadAsync(headersBuffer[n..headerSize], cancellationToken); + n += i; + } + while (n < headerSize && i > 0); + + stream.Position = startPosition; + + return InternalDetectFormat(configuration, headersBuffer.Span[..n]); + } + } + + private static IImageFormat InternalDetectFormat( + Configuration configuration, + ReadOnlySpan headersBuffer) + { // Does the given stream contain enough data to fit in the header for the format // and does that data match the format specification? // Individual formats should still check since they are public. IImageFormat? format = null; foreach (IImageFormatDetector formatDetector in configuration.ImageFormatsManager.FormatDetectors) { - if (formatDetector.HeaderSize <= headerSize && formatDetector.TryDetectFormat(headersBuffer, out IImageFormat? attemptFormat)) + if (formatDetector.HeaderSize <= headersBuffer.Length && formatDetector.TryDetectFormat(headersBuffer, out IImageFormat? attemptFormat)) { format = attemptFormat; } @@ -106,6 +157,22 @@ public abstract partial class Image return options.Configuration.ImageFormatsManager.GetDecoder(format); } + /// + /// By reading the header on the provided stream this calculates the images format. + /// + /// The general decoder options. + /// The image stream to read the header from. + /// The token to monitor for cancellation requests. + /// The . + private static async ValueTask DiscoverDecoderAsync( + DecoderOptions options, + Stream stream, + CancellationToken cancellationToken) + { + IImageFormat format = await InternalDetectFormatAsync(options.Configuration, stream, cancellationToken); + return options.Configuration.ImageFormatsManager.GetDecoder(format); + } + /// /// Decodes the image stream to the current image. /// @@ -122,14 +189,14 @@ public abstract partial class Image return decoder.Decode(options, stream); } - private static Task> DecodeAsync( + private static async Task> DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) where TPixel : unmanaged, IPixel { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.DecodeAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.DecodeAsync(options, stream, cancellationToken); } private static Image Decode(DecoderOptions options, Stream stream) @@ -138,13 +205,13 @@ public abstract partial class Image return decoder.Decode(options, stream); } - private static Task DecodeAsync( + private static async Task DecodeAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.DecodeAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.DecodeAsync(options, stream, cancellationToken); } /// @@ -166,12 +233,12 @@ public abstract partial class Image /// The stream. /// The token to monitor for cancellation requests. /// The . - private static Task InternalIdentifyAsync( + private static async Task InternalIdentifyAsync( DecoderOptions options, Stream stream, CancellationToken cancellationToken) { - IImageDecoder decoder = DiscoverDecoder(options, stream); - return decoder.IdentifyAsync(options, stream, cancellationToken); + IImageDecoder decoder = await DiscoverDecoderAsync(options, stream, cancellationToken); + return await decoder.IdentifyAsync(options, stream, cancellationToken); } } From 22e1c064c2825d7d5bb81c5040f0effb2dc6f0ff Mon Sep 17 00:00:00 2001 From: Dan Kroymann Date: Wed, 24 Apr 2024 18:20:34 -0700 Subject: [PATCH 213/219] Use MemoryAllocator from configuration --- src/ImageSharp/Image.Decode.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Image.Decode.cs b/src/ImageSharp/Image.Decode.cs index 8eec3c55f0..7f58c6ecd8 100644 --- a/src/ImageSharp/Image.Decode.cs +++ b/src/ImageSharp/Image.Decode.cs @@ -99,7 +99,7 @@ public abstract partial class Image ImageFormatManager.ThrowInvalidDecoder(configuration.ImageFormatsManager); } - using (IMemoryOwner memoryOwner = MemoryPool.Shared.Rent(headerSize)) + using (IMemoryOwner memoryOwner = configuration.MemoryAllocator.Allocate(headerSize)) { Memory headersBuffer = memoryOwner.Memory; long startPosition = stream.Position; From e0d1493c3b12788cb960c3c375d0e6ee1b0d39c0 Mon Sep 17 00:00:00 2001 From: Dan Kroymann Date: Wed, 24 Apr 2024 18:45:11 -0700 Subject: [PATCH 214/219] Call the new InternalDetectFormatAsync() from DetectFormatAsync() --- src/ImageSharp/Image.FromStream.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/ImageSharp/Image.FromStream.cs b/src/ImageSharp/Image.FromStream.cs index 63f9e64f6c..21345fdeb0 100644 --- a/src/ImageSharp/Image.FromStream.cs +++ b/src/ImageSharp/Image.FromStream.cs @@ -72,7 +72,7 @@ public abstract partial class Image => WithSeekableStreamAsync( options, stream, - (s, _) => Task.FromResult(InternalDetectFormat(options.Configuration, s)), + async (s, ct) => await InternalDetectFormatAsync(options.Configuration, s, ct).ConfigureAwait(false), cancellationToken); /// From 06312cbcfd98daec6b70b684a26e137440f82d7a Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Apr 2024 21:56:47 +0200 Subject: [PATCH 215/219] Update TestFormat.cs --- tests/ImageSharp.Tests/TestFormat.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 10211f386c..1c7d31b505 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -229,8 +229,7 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat return this.testFormat.Sample(); } - protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) - => this.Decode(options, stream, cancellationToken); + protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) => this.Decode(options, stream, cancellationToken); } public class TestDecoderOptions : ISpecializedDecoderOptions From eb1c871f79a0859fe68e34af391e73be68dc30ae Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Apr 2024 22:21:36 +0200 Subject: [PATCH 216/219] Update build-and-test.yml --- .github/workflows/build-and-test.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index d96bd90a93..a450aebf43 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -24,7 +24,7 @@ jobs: sdk: 8.0.x runtime: -x64 codecov: false - - os: macos-latest + - os: macos-13 # macos-latest runs on arm64 runners where libgdiplus is unavailable framework: net8.0 sdk: 8.0.x runtime: -x64 From aaeae24dd6b71ee2db7d465c336bbdca82988d5c Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Thu, 25 Apr 2024 22:28:42 +0200 Subject: [PATCH 217/219] Undo dummy change --- tests/ImageSharp.Tests/TestFormat.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/ImageSharp.Tests/TestFormat.cs b/tests/ImageSharp.Tests/TestFormat.cs index 1c7d31b505..10211f386c 100644 --- a/tests/ImageSharp.Tests/TestFormat.cs +++ b/tests/ImageSharp.Tests/TestFormat.cs @@ -229,7 +229,8 @@ public class TestFormat : IImageFormatConfigurationModule, IImageFormat return this.testFormat.Sample(); } - protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) => this.Decode(options, stream, cancellationToken); + protected override Image Decode(TestDecoderOptions options, Stream stream, CancellationToken cancellationToken) + => this.Decode(options, stream, cancellationToken); } public class TestDecoderOptions : ISpecializedDecoderOptions From 467850f7570fd79f3c2e144fceb57c5542cd2307 Mon Sep 17 00:00:00 2001 From: Anton Firszov Date: Wed, 8 May 2024 18:01:38 +0200 Subject: [PATCH 218/219] Fix overflow in MemoryAllocator.Create(options) (#2730) Fix an overlook from #2706. See https://github.com/SixLabors/ImageSharp/commit/92b82779ac8e7a032989533bb9a01ef092186b2e#r141770676. --- .../Memory/Allocators/MemoryAllocator.cs | 2 +- .../UniformUnmanagedPoolMemoryAllocatorTests.cs | 16 ++++++++++++++++ 2 files changed, 17 insertions(+), 1 deletion(-) diff --git a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs index b56bedd045..8eaf0b6d69 100644 --- a/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs +++ b/src/ImageSharp/Memory/Allocators/MemoryAllocator.cs @@ -49,7 +49,7 @@ public abstract class MemoryAllocator UniformUnmanagedMemoryPoolMemoryAllocator allocator = new(options.MaximumPoolSizeMegabytes); if (options.AllocationLimitMegabytes.HasValue) { - allocator.MemoryGroupAllocationLimitBytes = options.AllocationLimitMegabytes.Value * 1024 * 1024; + allocator.MemoryGroupAllocationLimitBytes = options.AllocationLimitMegabytes.Value * 1024L * 1024L; allocator.SingleBufferAllocationLimitBytes = (int)Math.Min(allocator.SingleBufferAllocationLimitBytes, allocator.MemoryGroupAllocationLimitBytes); } diff --git a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs index 077d0afed8..aa34a5c108 100644 --- a/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs +++ b/tests/ImageSharp.Tests/Memory/Allocators/UniformUnmanagedPoolMemoryAllocatorTests.cs @@ -442,4 +442,20 @@ public class UniformUnmanagedPoolMemoryAllocatorTests allocator.AllocateGroup(4 * oneMb, 1024).Dispose(); // Should work Assert.Throws(() => allocator.AllocateGroup(5 * oneMb, 1024)); } + + [ConditionalFact(typeof(Environment), nameof(Environment.Is64BitProcess))] + public void MemoryAllocator_Create_SetHighLimit() + { + RemoteExecutor.Invoke(RunTest).Dispose(); + static void RunTest() + { + const long threeGB = 3L * (1 << 30); + MemoryAllocator allocator = MemoryAllocator.Create(new MemoryAllocatorOptions() + { + AllocationLimitMegabytes = (int)(threeGB / 1024) + }); + using MemoryGroup memoryGroup = allocator.AllocateGroup(threeGB, 1024); + Assert.Equal(threeGB, memoryGroup.TotalLength); + } + } } From ede2f2d2d1e567dea74a44a482099302af9ed14d Mon Sep 17 00:00:00 2001 From: Brian Popow <38701097+brianpopow@users.noreply.github.com> Date: Fri, 7 Jun 2024 11:58:40 +0200 Subject: [PATCH 219/219] GifDecoder: Limit lzw bits to a maximum of 12 bits (#2744) * Limit lzw bits to a maximum of 12 bits, fixes issue #2743 * Dispose currentLocalColorTable in final block * Revert "Dispose currentLocalColorTable in final block" This reverts commit 35ea961552dc9a827c6b6119d9ba26b1dd8292fc. * Don't throw; return. --------- Co-authored-by: James Jackson-South --- src/ImageSharp/Formats/Gif/LzwDecoder.cs | 11 ++++++--- .../Formats/Gif/GifDecoderTests.cs | 23 +++++++++++-------- tests/ImageSharp.Tests/TestImages.cs | 1 + ...2012BadMinCode_Rgba32_issue2012_drona1.png | 3 +++ .../00.png | 3 +++ .../01.png | 3 +++ .../02.png | 3 +++ .../03.png | 3 +++ .../04.png | 3 +++ .../05.png | 3 +++ .../06.png | 3 +++ .../07.png | 3 +++ tests/Images/Input/Gif/issues/issue_2743.gif | 3 +++ 13 files changed, 53 insertions(+), 12 deletions(-) create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png create mode 100644 tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png create mode 100644 tests/Images/Input/Gif/issues/issue_2743.gif diff --git a/src/ImageSharp/Formats/Gif/LzwDecoder.cs b/src/ImageSharp/Formats/Gif/LzwDecoder.cs index 4d282f26c6..aecd8e5b47 100644 --- a/src/ImageSharp/Formats/Gif/LzwDecoder.cs +++ b/src/ImageSharp/Formats/Gif/LzwDecoder.cs @@ -19,6 +19,11 @@ internal sealed class LzwDecoder : IDisposable /// private const int MaxStackSize = 4096; + /// + /// The maximum bits for a lzw code. + /// + private const int MaximumLzwBits = 12; + /// /// The null code. /// @@ -73,12 +78,12 @@ internal sealed class LzwDecoder : IDisposable // It is possible to specify a larger LZW minimum code size than the palette length in bits // which may leave a gap in the codes where no colors are assigned. // http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression - if (minCodeSize < 2 || clearCode > MaxStackSize) + if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize) { // Don't attempt to decode the frame indices. // Theoretically we could determine a min code size from the length of the provided // color palette but we won't bother since the image is most likely corrupted. - GifThrowHelper.ThrowInvalidImageContentException("Gif Image does not contain a valid LZW minimum code."); + return; } // The resulting index table length. @@ -245,7 +250,7 @@ internal sealed class LzwDecoder : IDisposable // It is possible to specify a larger LZW minimum code size than the palette length in bits // which may leave a gap in the codes where no colors are assigned. // http://www.matthewflickinger.com/lab/whatsinagif/lzw_image_data.asp#lzw_compression - if (minCodeSize < 2 || clearCode > MaxStackSize) + if (minCodeSize < 2 || minCodeSize > MaximumLzwBits || clearCode > MaxStackSize) { // Don't attempt to decode the frame indices. // Theoretically we could determine a min code size from the length of the provided diff --git a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs index 6399e1193e..ee108b9d96 100644 --- a/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs +++ b/tests/ImageSharp.Tests/Formats/Gif/GifDecoderTests.cs @@ -296,15 +296,9 @@ public class GifDecoderTests public void Issue2012BadMinCode(TestImageProvider provider) where TPixel : unmanaged, IPixel { - Exception ex = Record.Exception( - () => - { - using Image image = provider.GetImage(); - image.DebugSave(provider); - }); - - Assert.NotNull(ex); - Assert.Contains("Gif Image does not contain a valid LZW minimum code.", ex.Message); + using Image image = provider.GetImage(); + image.DebugSave(provider); + image.CompareToReferenceOutput(provider); } // https://bugzilla.mozilla.org/show_bug.cgi?id=55918 @@ -318,4 +312,15 @@ public class GifDecoderTests image.DebugSave(provider); image.CompareFirstFrameToReferenceOutput(ImageComparer.Exact, provider); } + + // https://github.com/SixLabors/ImageSharp/issues/2743 + [Theory] + [WithFile(TestImages.Gif.Issues.BadMaxLzwBits, PixelTypes.Rgba32)] + public void IssueTooLargeLzwBits(TestImageProvider provider) + where TPixel : unmanaged, IPixel + { + using Image image = provider.GetImage(); + image.DebugSaveMultiFrame(provider); + image.CompareToReferenceOutputMultiFrame(provider, ImageComparer.Exact); + } } diff --git a/tests/ImageSharp.Tests/TestImages.cs b/tests/ImageSharp.Tests/TestImages.cs index a45931e29e..7aaaac6f81 100644 --- a/tests/ImageSharp.Tests/TestImages.cs +++ b/tests/ImageSharp.Tests/TestImages.cs @@ -516,6 +516,7 @@ public static class TestImages public const string BadAppExtLength = "Gif/issues/issue405_badappextlength252.gif"; public const string BadAppExtLength_2 = "Gif/issues/issue405_badappextlength252-2.gif"; public const string BadDescriptorWidth = "Gif/issues/issue403_baddescriptorwidth.gif"; + public const string BadMaxLzwBits = "Gif/issues/issue_2743.gif"; public const string DeferredClearCode = "Gif/issues/bugzilla-55918.gif"; public const string Issue1505 = "Gif/issues/issue1505_argumentoutofrange.png"; public const string Issue1530 = "Gif/issues/issue1530.gif"; diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png new file mode 100644 index 0000000000..cdba9277b1 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/Issue2012BadMinCode_Rgba32_issue2012_drona1.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:a3a24c066895fd3a76649da376485cbc1912d6a3ae15369575f523e66364b3b6 +size 141563 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png new file mode 100644 index 0000000000..923fbc1225 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/00.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:800d1ec2d7c7c99d449db1f49ef202cf18214016eae65ebc4216d6f4b1f4d328 +size 537 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png new file mode 100644 index 0000000000..6c2134d8b8 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/01.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:94dcd97831b16165f3331e429d72d7ef546e04038cab754c7918f9cf535ff30a +size 542 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png new file mode 100644 index 0000000000..6f50397ea4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/02.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec1a589a8fae1b17a82b70a9583ea2ee012a476b1fa8fdba27fee2b7ce0403b2 +size 540 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png new file mode 100644 index 0000000000..82061ba0aa --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/03.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c8751f4fafd5c56066dbb8d64a3890fc420a3bd66881a55e309ba274b6d14e4 +size 542 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png new file mode 100644 index 0000000000..8902eb824a --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/04.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:b78516c9874cb15de4c4b98ed307e8105d962fc6bfa7aa3490b2c7e13b455a2d +size 544 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png new file mode 100644 index 0000000000..82061ba0aa --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/05.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:0c8751f4fafd5c56066dbb8d64a3890fc420a3bd66881a55e309ba274b6d14e4 +size 542 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png new file mode 100644 index 0000000000..6f50397ea4 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/06.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:ec1a589a8fae1b17a82b70a9583ea2ee012a476b1fa8fdba27fee2b7ce0403b2 +size 540 diff --git a/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png new file mode 100644 index 0000000000..75cf685e43 --- /dev/null +++ b/tests/Images/External/ReferenceOutput/GifDecoderTests/IssueTooLargeLzwBits_Rgba32_issue_2743.gif/07.png @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:489642f0c81fd12e97007fe6feb11b0e93e351199a922ce038069a3782ad0722 +size 135 diff --git a/tests/Images/Input/Gif/issues/issue_2743.gif b/tests/Images/Input/Gif/issues/issue_2743.gif new file mode 100644 index 0000000000..4ce61340d9 --- /dev/null +++ b/tests/Images/Input/Gif/issues/issue_2743.gif @@ -0,0 +1,3 @@ +version https://git-lfs.github.com/spec/v1 +oid sha256:4be51cb9c258a6518d791ad2810fa0d71449805a5d5a8f95dcc7da2dc558ed73 +size 166413