mirror of https://github.com/SixLabors/ImageSharp
58 changed files with 1543 additions and 736 deletions
@ -0,0 +1,109 @@ |
|||
// <copyright file="YCbCrToRgbTables.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Formats.Jpg |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
using ImageSharp.PixelFormats; |
|||
|
|||
/// <summary>
|
|||
/// Provides 8-bit lookup tables for converting from YCbCr to Rgb colorspace.
|
|||
/// Methods to build the tables are based on libjpeg implementation.
|
|||
/// </summary>
|
|||
internal unsafe struct YCbCrToRgbTables |
|||
{ |
|||
/// <summary>
|
|||
/// The red red-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CrRTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The blue blue-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CbBTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The green red-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CrGTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The green blue-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CbGTable[256]; |
|||
|
|||
// Speediest right-shift on some machines and gives us enough accuracy at 4 decimal places.
|
|||
private const int ScaleBits = 16; |
|||
|
|||
private const int Half = 1 << (ScaleBits - 1); |
|||
|
|||
/// <summary>
|
|||
/// Initializes the YCbCr tables
|
|||
/// </summary>
|
|||
/// <returns>The intialized <see cref="YCbCrToRgbTables"/></returns>
|
|||
public static YCbCrToRgbTables Create() |
|||
{ |
|||
YCbCrToRgbTables tables = default(YCbCrToRgbTables); |
|||
|
|||
for (int i = 0, x = -128; i <= 255; i++, x++) |
|||
{ |
|||
// i is the actual input pixel value, in the range 0..255
|
|||
// The Cb or Cr value we are thinking of is x = i - 128
|
|||
// Cr=>R value is nearest int to 1.402 * x
|
|||
tables.CrRTable[i] = RightShift((Fix(1.402F) * x) + Half); |
|||
|
|||
// Cb=>B value is nearest int to 1.772 * x
|
|||
tables.CbBTable[i] = RightShift((Fix(1.772F) * x) + Half); |
|||
|
|||
// Cr=>G value is scaled-up -0.714136286
|
|||
tables.CrGTable[i] = (-Fix(0.714136286F)) * x; |
|||
|
|||
// Cb => G value is scaled - up - 0.344136286 * x
|
|||
// We also add in Half so that need not do it in inner loop
|
|||
tables.CbGTable[i] = ((-Fix(0.344136286F)) * x) + Half; |
|||
} |
|||
|
|||
return tables; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Optimized method to pack bytes to the image from the YCbCr color space.
|
|||
/// </summary>
|
|||
/// <typeparam name="TPixel">The pixel format.</typeparam>
|
|||
/// <param name="packed">The packed pixel.</param>
|
|||
/// <param name="tables">The reference to the tables instance.</param>
|
|||
/// <param name="y">The y luminance component.</param>
|
|||
/// <param name="cb">The cb chroma component.</param>
|
|||
/// <param name="cr">The cr chroma component.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void Pack<TPixel>(ref TPixel packed, YCbCrToRgbTables* tables, byte y, byte cb, byte cr) |
|||
where TPixel : struct, IPixel<TPixel> |
|||
{ |
|||
// float r = MathF.Round(y + (1.402F * cr), MidpointRounding.AwayFromZero);
|
|||
byte r = (byte)(y + tables->CrRTable[cr]).Clamp(0, 255); |
|||
|
|||
// float g = MathF.Round(y - (0.344136F * cb) - (0.714136F * cr), MidpointRounding.AwayFromZero);
|
|||
// The values for the G calculation are left scaled up, since we must add them together before rounding.
|
|||
byte g = (byte)(y + RightShift(tables->CbGTable[cb] + tables->CrGTable[cr])).Clamp(0, 255); |
|||
|
|||
// float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
|
|||
byte b = (byte)(y + tables->CbBTable[cb]).Clamp(0, 255); |
|||
|
|||
packed.PackFromBytes(r, g, b, byte.MaxValue); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int Fix(float x) |
|||
{ |
|||
return (int)((x * (1L << ScaleBits)) + 0.5F); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int RightShift(int x) |
|||
{ |
|||
return x >> ScaleBits; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,131 @@ |
|||
// <copyright file="RgbToYCbCrTables.cs" company="James Jackson-South">
|
|||
// Copyright (c) James Jackson-South and contributors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
// </copyright>
|
|||
|
|||
namespace ImageSharp.Formats.Jpg |
|||
{ |
|||
using System.Runtime.CompilerServices; |
|||
|
|||
/// <summary>
|
|||
/// Provides 8-bit lookup tables for converting from Rgb to YCbCr colorspace.
|
|||
/// Methods to build the tables are based on libjpeg implementation.
|
|||
/// </summary>
|
|||
internal unsafe struct RgbToYCbCrTables |
|||
{ |
|||
/// <summary>
|
|||
/// The red luminance table
|
|||
/// </summary>
|
|||
public fixed int YRTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The green luminance table
|
|||
/// </summary>
|
|||
public fixed int YGTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The blue luminance table
|
|||
/// </summary>
|
|||
public fixed int YBTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The red blue-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CbRTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The green blue-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CbGTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The blue blue-chrominance table
|
|||
/// B=>Cb and R=>Cr are the same
|
|||
/// </summary>
|
|||
public fixed int CbBTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The green red-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CrGTable[256]; |
|||
|
|||
/// <summary>
|
|||
/// The blue red-chrominance table
|
|||
/// </summary>
|
|||
public fixed int CrBTable[256]; |
|||
|
|||
// Speediest right-shift on some machines and gives us enough accuracy at 4 decimal places.
|
|||
private const int ScaleBits = 16; |
|||
|
|||
private const int CBCrOffset = 128 << ScaleBits; |
|||
|
|||
private const int Half = 1 << (ScaleBits - 1); |
|||
|
|||
/// <summary>
|
|||
/// Initializes the YCbCr tables
|
|||
/// </summary>
|
|||
/// <returns>The intialized <see cref="RgbToYCbCrTables"/></returns>
|
|||
public static RgbToYCbCrTables Create() |
|||
{ |
|||
RgbToYCbCrTables tables = default(RgbToYCbCrTables); |
|||
|
|||
for (int i = 0; i <= 255; i++) |
|||
{ |
|||
// The values for the calculations are left scaled up since we must add them together before rounding.
|
|||
tables.YRTable[i] = Fix(0.299F) * i; |
|||
tables.YGTable[i] = Fix(0.587F) * i; |
|||
tables.YBTable[i] = (Fix(0.114F) * i) + Half; |
|||
tables.CbRTable[i] = (-Fix(0.168735892F)) * i; |
|||
tables.CbGTable[i] = (-Fix(0.331264108F)) * i; |
|||
|
|||
// We use a rounding fudge - factor of 0.5 - epsilon for Cb and Cr.
|
|||
// This ensures that the maximum output will round to 255
|
|||
// not 256, and thus that we don't have to range-limit.
|
|||
//
|
|||
// B=>Cb and R=>Cr tables are the same
|
|||
tables.CbBTable[i] = (Fix(0.5F) * i) + CBCrOffset + Half - 1; |
|||
|
|||
tables.CrGTable[i] = (-Fix(0.418687589F)) * i; |
|||
tables.CrBTable[i] = (-Fix(0.081312411F)) * i; |
|||
} |
|||
|
|||
return tables; |
|||
} |
|||
|
|||
/// <summary>
|
|||
/// Optimized method to allocates the correct y, cb, and cr values to the DCT blocks from the given r, g, b values.
|
|||
/// </summary>
|
|||
/// <param name="yBlockRaw">The The luminance block.</param>
|
|||
/// <param name="cbBlockRaw">The red chroma block.</param>
|
|||
/// <param name="crBlockRaw">The blue chroma block.</param>
|
|||
/// <param name="tables">The reference to the tables instance.</param>
|
|||
/// <param name="index">The current index.</param>
|
|||
/// <param name="r">The red value.</param>
|
|||
/// <param name="g">The green value.</param>
|
|||
/// <param name="b">The blue value.</param>
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public static void Allocate(ref float* yBlockRaw, ref float* cbBlockRaw, ref float* crBlockRaw, ref RgbToYCbCrTables* tables, int index, int r, int g, int b) |
|||
{ |
|||
// float y = (0.299F * r) + (0.587F * g) + (0.114F * b);
|
|||
yBlockRaw[index] = (tables->YRTable[r] + tables->YGTable[g] + tables->YBTable[b]) >> ScaleBits; |
|||
|
|||
// float cb = 128F + ((-0.168736F * r) - (0.331264F * g) + (0.5F * b));
|
|||
cbBlockRaw[index] = (tables->CbRTable[r] + tables->CbGTable[g] + tables->CbBTable[b]) >> ScaleBits; |
|||
|
|||
// float b = MathF.Round(y + (1.772F * cb), MidpointRounding.AwayFromZero);
|
|||
crBlockRaw[index] = (tables->CbBTable[r] + tables->CrGTable[g] + tables->CrBTable[b]) >> ScaleBits; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int Fix(float x) |
|||
{ |
|||
return (int)((x * (1L << ScaleBits)) + 0.5F); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static int RightShift(int x) |
|||
{ |
|||
return x >> ScaleBits; |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:0677fbb7f1bd8dd19e8bd7ee802e07f3600193dafbfccf89f43e64e4fdf02d8f |
|||
size 15227 |
|||
Loading…
Reference in new issue