mirror of https://github.com/SixLabors/ImageSharp
committed by
GitHub
71 changed files with 1422 additions and 167 deletions
@ -0,0 +1,69 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Utils; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
/// <summary>
|
|||
/// Implements the 'BlackIsZero' photometric interpretation for 32-bit float grayscale images.
|
|||
/// </summary>
|
|||
internal class BlackIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly bool isBigEndian; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="BlackIsZero32FloatTiffColor{TPixel}" /> class.
|
|||
/// </summary>
|
|||
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
|
|||
public BlackIsZero32FloatTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) |
|||
{ |
|||
// Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
|
|||
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
|
|||
var color = default(TPixel); |
|||
color.FromVector4(TiffUtils.Vector4Default); |
|||
byte[] buffer = new byte[4]; |
|||
|
|||
int offset = 0; |
|||
for (int y = top; y < top + height; y++) |
|||
{ |
|||
Span<TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); |
|||
if (this.isBigEndian) |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
Array.Reverse(buffer); |
|||
float intensity = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
float intensity = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,88 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Utils; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
/// <summary>
|
|||
/// Implements the 'RGB' photometric interpretation with 32 bits for each channel.
|
|||
/// </summary>
|
|||
internal class RgbFloat323232TiffColor<TPixel> : TiffBaseColorDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly bool isBigEndian; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="RgbFloat323232TiffColor{TPixel}" /> class.
|
|||
/// </summary>
|
|||
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
|
|||
public RgbFloat323232TiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) |
|||
{ |
|||
// Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
|
|||
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
|
|||
var color = default(TPixel); |
|||
color.FromVector4(TiffUtils.Vector4Default); |
|||
int offset = 0; |
|||
byte[] buffer = new byte[4]; |
|||
|
|||
for (int y = top; y < top + height; y++) |
|||
{ |
|||
Span<TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); |
|||
|
|||
if (this.isBigEndian) |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
Array.Reverse(buffer); |
|||
float r = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
Array.Reverse(buffer); |
|||
float g = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
Array.Reverse(buffer); |
|||
float b = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(r, g, b, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
float r = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
float g = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
float b = BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(r, g, b, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,69 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Numerics; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Utils; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
/// <summary>
|
|||
/// Implements the 'WhiteIsZero' photometric interpretation for 32-bit float grayscale images.
|
|||
/// </summary>
|
|||
internal class WhiteIsZero32FloatTiffColor<TPixel> : TiffBaseColorDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly bool isBigEndian; |
|||
|
|||
/// <summary>
|
|||
/// Initializes a new instance of the <see cref="WhiteIsZero32FloatTiffColor{TPixel}" /> class.
|
|||
/// </summary>
|
|||
/// <param name="isBigEndian">if set to <c>true</c> decodes the pixel data as big endian, otherwise as little endian.</param>
|
|||
public WhiteIsZero32FloatTiffColor(bool isBigEndian) => this.isBigEndian = isBigEndian; |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) |
|||
{ |
|||
// Note: due to an issue with netcore 2.1 and default values and unpredictable behavior with those,
|
|||
// we define our own defaults as a workaround. See: https://github.com/dotnet/runtime/issues/55623
|
|||
var color = default(TPixel); |
|||
color.FromVector4(TiffUtils.Vector4Default); |
|||
byte[] buffer = new byte[4]; |
|||
|
|||
int offset = 0; |
|||
for (int y = top; y < top + height; y++) |
|||
{ |
|||
Span<TPixel> pixelRow = pixels.GetRowSpan(y).Slice(left, width); |
|||
if (this.isBigEndian) |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
Array.Reverse(buffer); |
|||
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
else |
|||
{ |
|||
for (int x = 0; x < pixelRow.Length; x++) |
|||
{ |
|||
data.Slice(offset, 4).CopyTo(buffer); |
|||
float intensity = 1.0f - BitConverter.ToSingle(buffer, 0); |
|||
offset += 4; |
|||
|
|||
var colorVector = new Vector4(intensity, intensity, intensity, 1.0f); |
|||
color.FromVector4(colorVector); |
|||
pixelRow[x] = color; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -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)Numerics.Clamp(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,80 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Utils; |
|||
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; |
|||
|
|||
private readonly ushort[] ycbcrSubSampling; |
|||
|
|||
public YCbCrPlanarTiffColor(Rational[] referenceBlackAndWhite, Rational[] coefficients, ushort[] ycbcrSubSampling) |
|||
{ |
|||
this.converter = new YCbCrConverter(referenceBlackAndWhite, coefficients); |
|||
this.ycbcrSubSampling = ycbcrSubSampling; |
|||
} |
|||
|
|||
/// <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(); |
|||
|
|||
if (this.ycbcrSubSampling != null && !(this.ycbcrSubSampling[0] == 1 && this.ycbcrSubSampling[1] == 1)) |
|||
{ |
|||
ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], cbData, crData); |
|||
} |
|||
|
|||
var color = default(TPixel); |
|||
int offset = 0; |
|||
int widthPadding = 0; |
|||
if (this.ycbcrSubSampling != null) |
|||
{ |
|||
// Round to the next integer multiple of horizontalSubSampling.
|
|||
widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[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++; |
|||
} |
|||
|
|||
offset += widthPadding; |
|||
} |
|||
} |
|||
|
|||
private static void ReverseChromaSubSampling(int width, int height, int horizontalSubSampling, int verticalSubSampling, Span<byte> planarCb, Span<byte> planarCr) |
|||
{ |
|||
// If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively,
|
|||
// then the source data will be padded.
|
|||
width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); |
|||
height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); |
|||
|
|||
for (int row = height - 1; row >= 0; row--) |
|||
{ |
|||
for (int col = width - 1; col >= 0; col--) |
|||
{ |
|||
int offset = (row * width) + col; |
|||
int subSampleOffset = (row / verticalSubSampling * (width / horizontalSubSampling)) + (col / horizontalSubSampling); |
|||
planarCb[offset] = planarCb[subSampleOffset]; |
|||
planarCr[offset] = planarCr[subSampleOffset]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,102 @@ |
|||
// Copyright (c) Six Labors.
|
|||
// Licensed under the Apache License, Version 2.0.
|
|||
|
|||
using System; |
|||
using System.Buffers; |
|||
using SixLabors.ImageSharp.Formats.Tiff.Utils; |
|||
using SixLabors.ImageSharp.Memory; |
|||
using SixLabors.ImageSharp.PixelFormats; |
|||
|
|||
namespace SixLabors.ImageSharp.Formats.Tiff.PhotometricInterpretation |
|||
{ |
|||
internal class YCbCrTiffColor<TPixel> : TiffBaseColorDecoder<TPixel> |
|||
where TPixel : unmanaged, IPixel<TPixel> |
|||
{ |
|||
private readonly MemoryAllocator memoryAllocator; |
|||
|
|||
private readonly YCbCrConverter converter; |
|||
|
|||
private readonly ushort[] ycbcrSubSampling; |
|||
|
|||
public YCbCrTiffColor(MemoryAllocator memoryAllocator, Rational[] referenceBlackAndWhite, Rational[] coefficients, ushort[] ycbcrSubSampling) |
|||
{ |
|||
this.memoryAllocator = memoryAllocator; |
|||
this.converter = new YCbCrConverter(referenceBlackAndWhite, coefficients); |
|||
this.ycbcrSubSampling = ycbcrSubSampling; |
|||
} |
|||
|
|||
/// <inheritdoc/>
|
|||
public override void Decode(ReadOnlySpan<byte> data, Buffer2D<TPixel> pixels, int left, int top, int width, int height) |
|||
{ |
|||
ReadOnlySpan<byte> ycbcrData = data; |
|||
if (this.ycbcrSubSampling != null && !(this.ycbcrSubSampling[0] == 1 && this.ycbcrSubSampling[1] == 1)) |
|||
{ |
|||
// 4 extra rows and columns for possible padding.
|
|||
int paddedWidth = width + 4; |
|||
int paddedHeight = height + 4; |
|||
int requiredBytes = paddedWidth * paddedHeight * 3; |
|||
using IMemoryOwner<byte> tmpBuffer = this.memoryAllocator.Allocate<byte>(requiredBytes); |
|||
Span<byte> tmpBufferSpan = tmpBuffer.GetSpan(); |
|||
ReverseChromaSubSampling(width, height, this.ycbcrSubSampling[0], this.ycbcrSubSampling[1], data, tmpBufferSpan); |
|||
ycbcrData = tmpBufferSpan; |
|||
} |
|||
|
|||
var color = default(TPixel); |
|||
int offset = 0; |
|||
int widthPadding = 0; |
|||
if (this.ycbcrSubSampling != null) |
|||
{ |
|||
// Round to the next integer multiple of horizontalSubSampling.
|
|||
widthPadding = TiffUtils.PaddingToNextInteger(width, this.ycbcrSubSampling[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(ycbcrData[offset], ycbcrData[offset + 1], ycbcrData[offset + 2]); |
|||
color.FromRgba32(rgba); |
|||
pixelRow[x] = color; |
|||
offset += 3; |
|||
} |
|||
|
|||
offset += widthPadding * 3; |
|||
} |
|||
} |
|||
|
|||
private static void ReverseChromaSubSampling(int width, int height, int horizontalSubSampling, int verticalSubSampling, ReadOnlySpan<byte> source, Span<byte> destination) |
|||
{ |
|||
// If width and height are not multiples of ChromaSubsampleHoriz and ChromaSubsampleVert respectively,
|
|||
// then the source data will be padded.
|
|||
width += TiffUtils.PaddingToNextInteger(width, horizontalSubSampling); |
|||
height += TiffUtils.PaddingToNextInteger(height, verticalSubSampling); |
|||
int blockWidth = width / horizontalSubSampling; |
|||
int blockHeight = height / verticalSubSampling; |
|||
int cbCrOffsetInBlock = horizontalSubSampling * verticalSubSampling; |
|||
int blockByteCount = cbCrOffsetInBlock + 2; |
|||
|
|||
for (int blockRow = blockHeight - 1; blockRow >= 0; blockRow--) |
|||
{ |
|||
for (int blockCol = blockWidth - 1; blockCol >= 0; blockCol--) |
|||
{ |
|||
int blockOffset = (blockRow * blockWidth) + blockCol; |
|||
ReadOnlySpan<byte> blockData = source.Slice(blockOffset * blockByteCount, blockByteCount); |
|||
byte cr = blockData[cbCrOffsetInBlock + 1]; |
|||
byte cb = blockData[cbCrOffsetInBlock]; |
|||
|
|||
for (int row = verticalSubSampling - 1; row >= 0; row--) |
|||
{ |
|||
for (int col = horizontalSubSampling - 1; col >= 0; col--) |
|||
{ |
|||
int offset = 3 * ((((blockRow * verticalSubSampling) + row) * width) + (blockCol * horizontalSubSampling) + col); |
|||
destination[offset + 2] = cr; |
|||
destination[offset + 1] = cb; |
|||
destination[offset] = blockData[(row * horizontalSubSampling) + col]; |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
} |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:3c72235954cdfb9d0cc7f09c537704e617313dc77708b4dca27b47c94c5e67a6 |
|||
size 2852 |
|||
@ -1,3 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:622d69dba0a8a67aa3b87e384a2b9ea8d29689eaa5cb5d0eee857f98ed660517 |
|||
size 15154924 |
|||
oid sha256:579db6b2bd34566846de992f255c6b341d0f88d957a0eb02b01caad3f20c5b44 |
|||
size 78794 |
|||
|
|||
@ -1,3 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:8b9b105857723bca5f478a9ab23c0aeca93abe863781019bbd2da47f18c46f24 |
|||
size 125778 |
|||
oid sha256:bba35f1e43c8425f3bcfab682efae4d2c00c62f0d8a4b411e646d32047469526 |
|||
size 125802 |
|||
|
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:37c6a28f460d8781fdc3bcf0cc9bd23f633b03899563546bfc6234a8478f67f0 |
|||
size 68637 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:eb56b3582c5c7d91d712e68181110ab0bf74d21992030629f05803c420b7b483 |
|||
size 388 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:5ac3e56a93996464a579ae19cf5f8d9531e2f08db36879aaba176731c24951a5 |
|||
size 352 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:cf75c4b679d2449e239f228cdee6a25adc7d7b16dde3fb9061a07b2fb0699db1 |
|||
size 735412 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:263da6b84862af1bc23f2631e648b1a629b5571b253c82f3ea64f44e9b7b1fe6 |
|||
size 8478 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:e67ac19cbdeb8585b204ee958edc7679a92c2b415a1a2c6051f14fe2966f933c |
|||
size 8504 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:d5e7998cc985ef11ab9da410f18dcfb6b9a3169fb1ec01f9e61aa38d8ee4cfb6 |
|||
size 12704 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:630e7f46655b6e61c4de7d56946a3a9225db68f776f9062ff2d5372547cc7c02 |
|||
size 12704 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:af82e07e6298082c91d60a97acb29b67ecabf386bc14371fcb698b248cfd3b40 |
|||
size 12814 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:5c918b8aa9968c03c12d85b3bcacd35ae57663a19f5490fc1c351521ed835f30 |
|||
size 12814 |
|||
@ -1,3 +0,0 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:514417ead3d6c5c6ca33374ef0bb6ecbe5f875a266519d4cbaa4a6b91033d243 |
|||
size 12778 |
|||
@ -1,3 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:64c948aa03bc4a24cd1d68bb18b5031c119936154a90f1cb1d9aaabd854c5d9b |
|||
oid sha256:17139bc00d9fe2905fbac9226120d2823ea17a10a39b140970122153ec23265d |
|||
size 12778 |
|||
|
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:17139bc00d9fe2905fbac9226120d2823ea17a10a39b140970122153ec23265d |
|||
size 12778 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:93e06533486f15e33f2435d081713fbecc3ba96c842058b7ba3a5d9116fe5f5c |
|||
size 12814 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:800a101f4d23fa2a499fcef036ebfca7d9338ac71b06a32ad05e7eb1905ddae3 |
|||
size 12814 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:dd1333eb93d8e7ea614b755ca1c8909c67b4b44fc03a8cab6be5491bf4d15841 |
|||
size 9753 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:eb465c21009def345d192319ba13ba2e1e537310eec3ab2cce680f0d111a4f18 |
|||
size 18256 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:c098beb9c8f250e9d4f6eb66a3a42f3852ad3ca86aabbdbacfa897d93ec8bc0d |
|||
size 18254 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:3ed60ad91ea70db01789f9dd37745d8a5ab86f72b98637cf2007b4e28a71976f |
|||
size 37632 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:1086c2ec568c5c3c2b08fcc66691fab017eb6fad109373a1dadd2e12fae86bc8 |
|||
size 37630 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:a1f889baa6f3bb99f15609848cdd47d548d3e2ed1b7b558d428550dfa3bd4bf9 |
|||
size 38050 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:2c02be5dff2bcd5d60afbf379ba9095b0c8fd3a7a0063f684ac9ac9119f967a5 |
|||
size 38050 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:95f7b71c3a333734f799d73076032e31a6dfff1802bb3b454ba1eada7be50b0d |
|||
size 10058 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:270e0331818a755f5fac600172eacbcbebda86f93f521bfc8d75f4b8bc530177 |
|||
size 6944 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:7ef6ebc9dfe72fbe6ed65ebfc2465ebb18f326119a640faf3301aa4cfa31990f |
|||
size 5464 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:c5ea966cc7b823a5d228b49cdc55a261353f73b1eb94a218f1c68321d757e25f |
|||
size 4342 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:cdc4d8033214a6737f41c4e32d9314db77b3b1ae14515496f10468047390f6c5 |
|||
size 10042 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:d5b2e1a17338133aa95cb8a16d82a171f5b50f7b9ae1a51ab06227dc3daa81d5 |
|||
size 50401 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:389ee18596cd3d9f1f7f04b4db8fd21edce2900837c17ebb57cc4b64a6820f3e |
|||
size 120354 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:95b1ba4ff48ea2263041eca4ada44d009277297bb3b3a185d48580bdf3f7caaf |
|||
size 81382 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:fbd835c2406700523b239b80299b2b02c36d41182ac338f7ed7164979a787c60 |
|||
size 63438 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:399d5bc062baa00c2054a138489709379032f8683fbcb292bb2125b62e715b5f |
|||
size 50336 |
|||
@ -0,0 +1,3 @@ |
|||
version https://git-lfs.github.com/spec/v1 |
|||
oid sha256:58c4914b32b27df1ef303bb127fe9211c2aeda23e17bb5f4b349543c96d845b7 |
|||
size 45152 |
|||
Loading…
Reference in new issue