Browse Source

Fix predictor encoder on NET472 32bit.

pull/1552/head
James Jackson-South 5 years ago
parent
commit
dafafb8f21
  1. 18
      src/ImageSharp/Formats/WebP/Lossless/PredictorEncoder.cs
  2. 13
      tests/ImageSharp.Tests/Formats/WebP/PredictorEncoderTests.cs

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

@ -798,7 +798,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
{ {
int maxIters = 4 + ((7 * quality) >> 8); // in range [4..6] int maxIters = 4 + ((7 * quality) >> 8); // in range [4..6]
int greenToRedBest = 0; int greenToRedBest = 0;
float bestDiff = GetPredictionCostCrossColorRed(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToRedBest, accumulatedRedHisto); double bestDiff = GetPredictionCostCrossColorRed(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToRedBest, accumulatedRedHisto);
for (int iter = 0; iter < maxIters; iter++) for (int iter = 0; iter < maxIters; iter++)
{ {
// ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to // ColorTransformDelta is a 3.5 bit fixed point, so 32 is equal to
@ -810,7 +810,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
for (int offset = -delta; offset <= delta; offset += 2 * delta) for (int offset = -delta; offset <= delta; offset += 2 * delta)
{ {
int greenToRedCur = offset + greenToRedBest; int greenToRedCur = offset + greenToRedBest;
float curDiff = GetPredictionCostCrossColorRed(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToRedCur, accumulatedRedHisto); double curDiff = GetPredictionCostCrossColorRed(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToRedCur, accumulatedRedHisto);
if (curDiff < bestDiff) if (curDiff < bestDiff)
{ {
bestDiff = curDiff; bestDiff = curDiff;
@ -831,7 +831,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
sbyte[] deltaLut = { 16, 16, 8, 4, 2, 2, 2 }; sbyte[] deltaLut = { 16, 16, 8, 4, 2, 2, 2 };
// Initial value at origin: // Initial value at origin:
float bestDiff = GetPredictionCostCrossColorBlue(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToBlueBest, redToBlueBest, accumulatedBlueHisto); double bestDiff = GetPredictionCostCrossColorBlue(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToBlueBest, redToBlueBest, accumulatedBlueHisto);
for (int iter = 0; iter < iters; iter++) for (int iter = 0; iter < iters; iter++)
{ {
int delta = deltaLut[iter]; int delta = deltaLut[iter];
@ -839,7 +839,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
{ {
int greenToBlueCur = (offset[axis][0] * delta) + greenToBlueBest; int greenToBlueCur = (offset[axis][0] * delta) + greenToBlueBest;
int redToBlueCur = (offset[axis][1] * delta) + redToBlueBest; int redToBlueCur = (offset[axis][1] * delta) + redToBlueBest;
float curDiff = GetPredictionCostCrossColorBlue(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToBlueCur, redToBlueCur, accumulatedBlueHisto); double curDiff = GetPredictionCostCrossColorBlue(argb, stride, tileWidth, tileHeight, prevX, prevY, greenToBlueCur, redToBlueCur, accumulatedBlueHisto);
if (curDiff < bestDiff) if (curDiff < bestDiff)
{ {
bestDiff = curDiff; bestDiff = curDiff;
@ -865,12 +865,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
bestTx.RedToBlue = (byte)(redToBlueBest & 0xff); bestTx.RedToBlue = (byte)(redToBlueBest & 0xff);
} }
private static float GetPredictionCostCrossColorRed(Span<uint> argb, int stride, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, int greenToRed, int[] accumulatedRedHisto) private static double GetPredictionCostCrossColorRed(Span<uint> argb, int stride, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, int greenToRed, int[] accumulatedRedHisto)
{ {
int[] histo = new int[256]; int[] histo = new int[256];
CollectColorRedTransforms(argb, stride, tileWidth, tileHeight, greenToRed, histo); CollectColorRedTransforms(argb, stride, tileWidth, tileHeight, greenToRed, histo);
float curDiff = PredictionCostCrossColor(accumulatedRedHisto, histo); double curDiff = PredictionCostCrossColor(accumulatedRedHisto, histo);
if ((byte)greenToRed == prevX.GreenToRed) if ((byte)greenToRed == prevX.GreenToRed)
{ {
@ -890,12 +890,12 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
return curDiff; return curDiff;
} }
private static float GetPredictionCostCrossColorBlue(Span<uint> argb, int stride, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, int greenToBlue, int redToBlue, int[] accumulatedBlueHisto) private static double GetPredictionCostCrossColorBlue(Span<uint> argb, int stride, int tileWidth, int tileHeight, Vp8LMultipliers prevX, Vp8LMultipliers prevY, int greenToBlue, int redToBlue, int[] accumulatedBlueHisto)
{ {
int[] histo = new int[256]; int[] histo = new int[256];
CollectColorBlueTransforms(argb, stride, tileWidth, tileHeight, greenToBlue, redToBlue, histo); CollectColorBlueTransforms(argb, stride, tileWidth, tileHeight, greenToBlue, redToBlue, histo);
float curDiff = PredictionCostCrossColor(accumulatedBlueHisto, histo); double curDiff = PredictionCostCrossColor(accumulatedBlueHisto, histo);
if ((byte)greenToBlue == prevX.GreenToBlue) if ((byte)greenToBlue == prevX.GreenToBlue)
{ {
curDiff -= 3; // Favor keeping the areas locally similar. curDiff -= 3; // Favor keeping the areas locally similar.
@ -1088,7 +1088,7 @@ namespace SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless
} }
[MethodImpl(InliningOptions.ShortMethod)] [MethodImpl(InliningOptions.ShortMethod)]
private static float PredictionCostCrossColor(int[] accumulated, int[] counts) private static double PredictionCostCrossColor(int[] accumulated, int[] counts)
{ {
// Favor low entropy, locally and globally. // Favor low entropy, locally and globally.
// Favor small absolute values for PredictionCostSpatial. // Favor small absolute values for PredictionCostSpatial.

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

@ -6,7 +6,9 @@ using System.IO;
using SixLabors.ImageSharp.Formats.Experimental.Webp; using SixLabors.ImageSharp.Formats.Experimental.Webp;
using SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless; using SixLabors.ImageSharp.Formats.Experimental.Webp.Lossless;
using SixLabors.ImageSharp.PixelFormats; using SixLabors.ImageSharp.PixelFormats;
#if SUPPORTS_RUNTIME_INTRINSICS
using SixLabors.ImageSharp.Tests.TestUtilities; using SixLabors.ImageSharp.Tests.TestUtilities;
#endif
using Xunit; using Xunit;
namespace SixLabors.ImageSharp.Tests.Formats.WebP namespace SixLabors.ImageSharp.Tests.Formats.WebP
@ -16,18 +18,11 @@ namespace SixLabors.ImageSharp.Tests.Formats.WebP
{ {
[Fact] [Fact]
public static void ColorSpaceTransform_WithBikeImage_ProducesExpectedData() public static void ColorSpaceTransform_WithBikeImage_ProducesExpectedData()
{ => RunColorSpaceTransformTestWithBikeImage();
RunColorSpaceTransformTestWithBikeImage();
}
// Note: only run with netcoreapp, because the test fails with net472 in Release mode (not in Debug mode) for unknown reason.
#if NETCOREAPP
[Fact] [Fact]
public static void ColorSpaceTransform_WithPeakImage_ProducesExpectedData() public static void ColorSpaceTransform_WithPeakImage_ProducesExpectedData()
{ => RunColorSpaceTransformTestWithPeakImage();
RunColorSpaceTransformTestWithPeakImage();
}
#endif
#if SUPPORTS_RUNTIME_INTRINSICS #if SUPPORTS_RUNTIME_INTRINSICS
[Fact] [Fact]

Loading…
Cancel
Save