// Copyright (c) Six Labors and contributors. // Licensed under the Apache License, Version 2.0. // ReSharper disable InconsistentNaming using System; using System.Runtime.CompilerServices; using SixLabors.ImageSharp.Formats.Jpeg.Components; namespace SixLabors.ImageSharp.Tests.Formats.Jpg.Utils { /// /// This class contains simplified (inefficient) reference implementations to produce verification data for unit tests /// Floating point DCT code Ported from https://github.com/norishigefukushima/dct_simd /// internal static partial class ReferenceImplementations { public static unsafe void DequantizeBlock(Block8x8F* blockPtr, Block8x8F* qtPtr, byte* unzigPtr) { float* b = (float*)blockPtr; float* qtp = (float*)qtPtr; for (int qtIndex = 0; qtIndex < Block8x8F.Size; qtIndex++) { byte i = unzigPtr[qtIndex]; float* unzigPos = b + i; float val = *unzigPos; val *= qtp[qtIndex]; *unzigPos = val; } } /// /// Transpose 8x8 block stored linearly in a (inplace) /// /// internal static void Transpose8x8(Span data) { for (int i = 1; i < 8; i++) { int i8 = i * 8; for (int j = 0; j < i; j++) { float tmp = data[i8 + j]; data[i8 + j] = data[j * 8 + i]; data[j * 8 + i] = tmp; } } } /// /// Transpose 8x8 block stored linearly in a /// internal static void Transpose8x8(Span src, Span dest) { for (int i = 0; i < 8; i++) { int i8 = i * 8; for (int j = 0; j < 8; j++) { dest[j * 8 + i] = src[i8 + j]; } } } /// /// Copies color values from block to the destination image buffer. /// /// /// /// internal static unsafe void CopyColorsTo(ref Block8x8F block, Span buffer, int stride) { fixed (Block8x8F* p = &block) { float* b = (float*)p; for (int y = 0; y < 8; y++) { int y8 = y * 8; int yStride = y * stride; for (int x = 0; x < 8; x++) { float c = b[y8 + x]; if (c < -128) { c = 0; } else if (c > 127) { c = 255; } else { c += 128; } buffer[yStride + x] = (byte)c; } } } } /// /// Reference implementation to test . /// Rounding is done used an integer-based algorithm defined in . /// /// The input block /// The destination block of integers /// The quantization table /// Pointer to public static unsafe void QuantizeRational(Block8x8F* src, int* dest, Block8x8F* qt, byte* unzigPtr) { float* s = (float*)src; float* q = (float*)qt; for (int zig = 0; zig < Block8x8F.Size; zig++) { int a = (int)s[unzigPtr[zig]]; int b = (int)q[zig]; int val = RationalRound(a, b); dest[zig] = val; } } /// /// Rounds a rational number defined as dividend/divisor into an integer /// /// The dividend /// The divisor /// [MethodImpl(MethodImplOptions.AggressiveInlining)] private static int RationalRound(int dividend, int divisor) { if (dividend >= 0) { return (dividend + (divisor >> 1)) / divisor; } return -((-dividend + (divisor >> 1)) / divisor); } } }