mirror of https://github.com/SixLabors/ImageSharp
9 changed files with 205 additions and 82 deletions
@ -0,0 +1,121 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Runtime.CompilerServices; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
/// <summary>
|
|||
/// Converts YCbCr data to rgb data.
|
|||
/// </summary>
|
|||
internal class YCbCrConverter |
|||
{ |
|||
private readonly CodingRangeExpander yExpander; |
|||
private readonly CodingRangeExpander cbExpander; |
|||
private readonly CodingRangeExpander crExpander; |
|||
private readonly YCbCrToRgbConverter converter; |
|||
|
|||
private static readonly Rational[] DefaultLuma = |
|||
{ |
|||
new Rational(299, 1000), |
|||
new Rational(587, 1000), |
|||
new Rational(114, 1000) |
|||
}; |
|||
|
|||
private static readonly Rational[] DefaultReferenceBlackWhite = |
|||
{ |
|||
new Rational(0, 1), new Rational(255, 1), |
|||
new Rational(128, 1), new Rational(255, 1), |
|||
new Rational(128, 1), new Rational(255, 1) |
|||
}; |
|||
|
|||
public YCbCrConverter(Rational[] referenceBlackAndWhite, Rational[] coefficients) |
|||
{ |
|||
referenceBlackAndWhite ??= DefaultReferenceBlackWhite; |
|||
coefficients ??= DefaultLuma; |
|||
|
|||
if (referenceBlackAndWhite.Length != 6) |
|||
{ |
|||
TiffThrowHelper.ThrowImageFormatException("reference black and white array should have 6 entry's"); |
|||
} |
|||
|
|||
if (coefficients.Length != 3) |
|||
{ |
|||
TiffThrowHelper.ThrowImageFormatException("luma coefficients array should have 6 entry's"); |
|||
} |
|||
|
|||
this.yExpander = new CodingRangeExpander(referenceBlackAndWhite[0], referenceBlackAndWhite[1], 255); |
|||
this.cbExpander = new CodingRangeExpander(referenceBlackAndWhite[2], referenceBlackAndWhite[3], 127); |
|||
this.crExpander = new CodingRangeExpander(referenceBlackAndWhite[4], referenceBlackAndWhite[5], 127); |
|||
this.converter = new YCbCrToRgbConverter(coefficients[0], coefficients[1], coefficients[2]); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba32 ConvertToRgba32(byte y, byte cb, byte cr) |
|||
{ |
|||
float yExpanded = this.yExpander.Expand(y); |
|||
float cbExpanded = this.cbExpander.Expand(cb); |
|||
float crExpanded = this.crExpander.Expand(cr); |
|||
|
|||
Rgba32 rgba = this.converter.Convert(yExpanded, cbExpanded, crExpanded); |
|||
|
|||
return rgba; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
private static byte RoundAndClampTo8Bit(float value) |
|||
{ |
|||
int input = (int)MathF.Round(value); |
|||
return (byte)Math.Min(Math.Max(input, 0), 255); |
|||
} |
|||
|
|||
private readonly struct CodingRangeExpander |
|||
{ |
|||
private readonly float f1; |
|||
private readonly float f2; |
|||
|
|||
public CodingRangeExpander(Rational referenceBlack, Rational referenceWhite, int codingRange) |
|||
{ |
|||
float black = referenceBlack.ToSingle(); |
|||
float white = referenceWhite.ToSingle(); |
|||
this.f1 = codingRange / (white - black); |
|||
this.f2 = this.f1 * black; |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public float Expand(float code) => (code * this.f1) - this.f2; |
|||
} |
|||
|
|||
private readonly struct YCbCrToRgbConverter |
|||
{ |
|||
private readonly float cr2R; |
|||
private readonly float cb2B; |
|||
private readonly float y2G; |
|||
private readonly float cr2G; |
|||
private readonly float cb2G; |
|||
|
|||
public YCbCrToRgbConverter(Rational lumaRed, Rational lumaGreen, Rational lumaBlue) |
|||
{ |
|||
this.cr2R = 2 - (2 * lumaRed.ToSingle()); |
|||
this.cb2B = 2 - (2 * lumaBlue.ToSingle()); |
|||
this.y2G = (1 - lumaBlue.ToSingle() - lumaRed.ToSingle()) / lumaGreen.ToSingle(); |
|||
this.cr2G = 2 * lumaRed.ToSingle() * (lumaRed.ToSingle() - 1) / lumaGreen.ToSingle(); |
|||
this.cb2G = 2 * lumaBlue.ToSingle() * (lumaBlue.ToSingle() - 1) / lumaGreen.ToSingle(); |
|||
} |
|||
|
|||
[MethodImpl(MethodImplOptions.AggressiveInlining)] |
|||
public Rgba32 Convert(float y, float cb, float cr) |
|||
{ |
|||
var pixel = default(Rgba32); |
|||
pixel.R = RoundAndClampTo8Bit((cr * this.cr2R) + y); |
|||
pixel.G = RoundAndClampTo8Bit((this.y2G * y) + (this.cr2G * cr) + (this.cb2G * cb)); |
|||
pixel.B = RoundAndClampTo8Bit((cb * this.cb2B) + y); |
|||
pixel.A = byte.MaxValue; |
|||
|
|||
return pixel; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,40 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
internal class YCbCrPlanarTiffColor<TPixel> : TiffBasePlanarColorDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly YCbCrConverter converter; |
|||
|
|||
public YCbCrPlanarTiffColor(Rational[] referenceBlackAndWhite, Rational[] coefficients) => this.converter = new YCbCrConverter(referenceBlackAndWhite, coefficients); |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Decode(IMemoryOwner<byte>[] data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) |
|||
{ |
|||
Span<byte> yData = data[0].GetSpan(); |
|||
Span<byte> cbData = data[1].GetSpan(); |
|||
Span<byte> crData = data[2].GetSpan(); |
|||
|
|||
var color = default(TPixel); |
|||
int offset = 0; |
|||
for (int y = top; y < top + height; y++) |
|||
{ |
|||
Span<TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
Rgba32 rgba = this.converter.ConvertToRgba32(yData[offset], cbData[offset], crData[offset]); |
|||
color.FromRgba32(rgba); |
|||
pixelRow[x] = color; |
|||
offset++; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:cdc4d8033214a6737f41c4e32d9314db77b3b1ae14515496f10468047390f6c5 |
|||
size 10042 |
|||
Loading…
Reference in new issue