Created
April 24, 2017 23:19
-
-
Save JimBobSquarePants/2d7c2d0e62df76ef9c24ebd12ea62ad6 to your computer and use it in GitHub Desktop.
LUT Tables for YCbCr -> Rgb conversion method
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// <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.Jpeg.Components.Decoder | |
{ | |
using System.Runtime.CompilerServices; | |
using ImageSharp.PixelFormats; | |
/// <summary> | |
/// Provides lookup tables for converting from YCbCr to Rgb colorspace. | |
/// Methods to build the tables are identical to libjpeg. | |
/// </summary> | |
internal struct YCbCrToRgbTables | |
{ | |
private const int ScaleBits = 16; | |
private const int Half = 1 << (ScaleBits - 1); | |
private static readonly int[] CrRTable = new int[256]; | |
private static readonly int[] CbBTable = new int[256]; | |
private static readonly int[] CrGTable = new int[256]; | |
private static readonly int[] CbGTable = new int[256]; | |
/// <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="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 void Pack<TPixel>(ref TPixel packed, byte y, byte cb, byte cr) | |
where TPixel : struct, IPixel<TPixel> | |
{ | |
byte r = (byte)(y + CrRTable[cr]).Clamp(0, 255); | |
// The values for the G calculation are left scaled up, since we must add them together before rounding. | |
byte g = (byte)(y + RightShift(CbGTable[cb] + CrGTable[cr])).Clamp(0, 255); | |
byte b = (byte)(y + CbBTable[cb]).Clamp(0, 255); | |
packed.PackFromBytes(r, g, b, byte.MaxValue); | |
} | |
/// <summary> | |
/// Initializes the YCbCr tables | |
/// </summary> | |
/// <returns>The intialized <see cref="YCbCrToRgbTables"/></returns> | |
public YCbCrToRgbTables Init() | |
{ | |
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 | |
CrRTable[i] = RightShift((Fix(1.402F) * x) + Half); | |
// Cb=>B value is nearest int to 1.772 * x | |
CbBTable[i] = RightShift((Fix(1.772F) * x) + Half); | |
// Cr=>G value is scaled-up -0.714136286 | |
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 | |
CbGTable[i] = ((-Fix(0.344136286F)) * x) + Half; | |
} | |
return this; | |
} | |
[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; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment