mirror of https://github.com/SixLabors/ImageSharp
9 changed files with 139 additions and 120 deletions
@ -0,0 +1,113 @@ |
|||||
|
// Copyright (c) Six Labors.
|
||||
|
// Licensed under the Apache License, Version 2.0.
|
||||
|
|
||||
|
using System; |
||||
|
using System.Runtime.CompilerServices; |
||||
|
|
||||
|
namespace SixLabors.ImageSharp.Formats.Jpeg.Components |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Contains floating point forward DCT implementations with built-in scaling.
|
||||
|
/// </summary>
|
||||
|
/// <remarks>
|
||||
|
/// Based on "Loeffler, Ligtenberg, and Moschytz" algorithm.
|
||||
|
/// </remarks>
|
||||
|
internal static class ScaledFloatingPointDCT |
||||
|
{ |
||||
|
/// <summary>
|
||||
|
/// Adjusts given quantization table for usage with IDCT algorithms
|
||||
|
/// from <see cref="ScaledFloatingPointDCT"/>.
|
||||
|
/// </summary>
|
||||
|
/// <param name="quantTable">Quantization table to adjust.</param>
|
||||
|
public static void AdjustToIDCT(ref Block8x8F quantTable) |
||||
|
{ |
||||
|
ref float tableRef = ref Unsafe.As<Block8x8F, float>(ref quantTable); |
||||
|
for (nint i = 0; i < Block8x8F.Size; i++) |
||||
|
{ |
||||
|
ref float elemRef = ref Unsafe.Add(ref tableRef, i); |
||||
|
elemRef = 0.125f * elemRef; |
||||
|
} |
||||
|
|
||||
|
// Spectral macroblocks are transposed before quantization
|
||||
|
// so we must transpose quantization table
|
||||
|
quantTable.TransposeInplace(); |
||||
|
} |
||||
|
|
||||
|
public static float TransformIDCT_1x1(float dc, float dequantizer, float normalizationValue, float maxValue) |
||||
|
=> MathF.Round(Numerics.Clamp((dc * dequantizer) + normalizationValue, 0, maxValue)); |
||||
|
|
||||
|
public static void TransformIDCT_2x2(ref Block8x8F block, ref Block8x8F dequantTable, float normalizationValue, float maxValue) |
||||
|
{ |
||||
|
float tmp4 = block[0] * dequantTable[0]; |
||||
|
float tmp5 = block[1] * dequantTable[1]; |
||||
|
float tmp0 = tmp4 + tmp5; |
||||
|
float tmp2 = tmp4 - tmp5; |
||||
|
|
||||
|
tmp4 = block[8] * dequantTable[8]; |
||||
|
tmp5 = block[9] * dequantTable[9]; |
||||
|
float tmp1 = tmp4 + tmp5; |
||||
|
float tmp3 = tmp4 - tmp5; |
||||
|
|
||||
|
block[0] = MathF.Round(Numerics.Clamp(tmp0 + tmp1 + normalizationValue, 0, maxValue)); |
||||
|
block[1] = MathF.Round(Numerics.Clamp(tmp0 - tmp1 + normalizationValue, 0, maxValue)); |
||||
|
block[8] = MathF.Round(Numerics.Clamp(tmp2 + tmp3 + normalizationValue, 0, maxValue)); |
||||
|
block[9] = MathF.Round(Numerics.Clamp(tmp2 - tmp3 + normalizationValue, 0, maxValue)); |
||||
|
} |
||||
|
|
||||
|
public static void TransformIDCT_4x4(ref Block8x8F block, ref Block8x8F dequantTable, float normalizationValue, float maxValue) |
||||
|
{ |
||||
|
const int DCTSIZE = 8; |
||||
|
const float FIX_0_541196100 = 0.541196100f; |
||||
|
const float FIX_0_765366865 = 0.765366865f; |
||||
|
const float FIX_1_847759065 = 1.847759065f; |
||||
|
|
||||
|
for (int ctr = 0; ctr < 4; ctr++) |
||||
|
{ |
||||
|
// Even part
|
||||
|
float tmp0 = block[ctr * DCTSIZE] * dequantTable[ctr * DCTSIZE]; |
||||
|
float tmp2 = block[(ctr * DCTSIZE) + 2] * dequantTable[(ctr * DCTSIZE) + 2]; |
||||
|
|
||||
|
float tmp10 = tmp0 + tmp2; |
||||
|
float tmp12 = tmp0 - tmp2; |
||||
|
|
||||
|
// Odd part
|
||||
|
float z2 = block[(ctr * DCTSIZE) + 1] * dequantTable[(ctr * DCTSIZE) + 1]; |
||||
|
float z3 = block[(ctr * DCTSIZE) + 3] * dequantTable[(ctr * DCTSIZE) + 3]; |
||||
|
|
||||
|
float z1 = (z2 + z3) * FIX_0_541196100; |
||||
|
tmp0 = z1 + (z2 * FIX_0_765366865); |
||||
|
tmp2 = z1 - (z3 * FIX_1_847759065); |
||||
|
|
||||
|
/* Final output stage */ |
||||
|
block[ctr + 4] = tmp10 + tmp0; |
||||
|
block[ctr + 28] = tmp10 - tmp0; |
||||
|
block[ctr + 12] = tmp12 + tmp2; |
||||
|
block[ctr + 20] = tmp12 - tmp2; |
||||
|
} |
||||
|
|
||||
|
for (int ctr = 0; ctr < 4; ctr++) |
||||
|
{ |
||||
|
// Even part
|
||||
|
float tmp0 = block[(ctr * 8) + 0 + 4]; |
||||
|
float tmp2 = block[(ctr * 8) + 2 + 4]; |
||||
|
|
||||
|
float tmp10 = tmp0 + tmp2; |
||||
|
float tmp12 = tmp0 - tmp2; |
||||
|
|
||||
|
// Odd part
|
||||
|
float z2 = block[(ctr * 8) + 1 + 4]; |
||||
|
float z3 = block[(ctr * 8) + 3 + 4]; |
||||
|
|
||||
|
float z1 = (z2 + z3) * FIX_0_541196100; |
||||
|
tmp0 = z1 + (z2 * FIX_0_765366865); |
||||
|
tmp2 = z1 - (z3 * FIX_1_847759065); |
||||
|
|
||||
|
/* Final output stage */ |
||||
|
block[(ctr * 8) + 0] = MathF.Round(Numerics.Clamp(tmp10 + tmp0 + normalizationValue, 0, maxValue)); |
||||
|
block[(ctr * 8) + 3] = MathF.Round(Numerics.Clamp(tmp10 - tmp0 + normalizationValue, 0, maxValue)); |
||||
|
block[(ctr * 8) + 1] = MathF.Round(Numerics.Clamp(tmp12 + tmp2 + normalizationValue, 0, maxValue)); |
||||
|
block[(ctr * 8) + 2] = MathF.Round(Numerics.Clamp(tmp12 - tmp2 + normalizationValue, 0, maxValue)); |
||||
|
} |
||||
|
} |
||||
|
} |
||||
|
} |
||||
Loading…
Reference in new issue