//
// Copyright (c) James Jackson-South and contributors.
// Licensed under the Apache License, Version 2.0.
//
namespace ImageSharp.Formats.Jpg
{
using System.Buffers;
using System.Runtime.CompilerServices;
///
/// Represents an area of a Jpeg subimage (channel)
///
internal struct JpegPixelArea
{
///
/// Initializes a new instance of the struct from existing data.
///
/// The pixel array
/// The stride
/// The offset
public JpegPixelArea(byte[] pixels, int striede, int offset)
{
this.Stride = striede;
this.Pixels = pixels;
this.Offset = offset;
}
///
/// Gets the pixels.
///
public byte[] Pixels { get; private set; }
///
/// Gets a value indicating whether the instance has been initalized. (Is not default(JpegPixelArea))
///
public bool IsInitialized => this.Pixels != null;
///
/// Gets or the stride.
///
public int Stride { get; }
///
/// Gets or the offset.
///
public int Offset { get; }
///
/// Gets a of bytes to the pixel area
///
public MutableSpan Span => new MutableSpan(this.Pixels, this.Offset);
private static ArrayPool BytePool => ArrayPool.Shared;
///
/// Returns the pixel at (x, y)
///
/// The x index
/// The y index
/// The pixel value
public byte this[int x, int y]
{
[MethodImpl(MethodImplOptions.AggressiveInlining)]
get
{
return this.Pixels[(y * this.Stride) + x];
}
}
///
/// Creates a new instance of the struct.
/// Pixel array will be taken from a pool, this instance will be the owner of it's pixel data, therefore
/// should be called when the instance is no longer needed.
///
/// The width.
/// The height.
/// A with pooled data
public static JpegPixelArea CreatePooled(int width, int height)
{
int size = width * height;
var pixels = BytePool.Rent(size);
return new JpegPixelArea(pixels, width, 0);
}
///
/// Returns to the pool
///
public void ReturnPooled()
{
if (this.Pixels == null)
{
return;
}
BytePool.Return(this.Pixels);
this.Pixels = null;
}
///
/// Gets the subarea that belongs to the Block8x8 defined by block indices
///
/// The block X index
/// The block Y index
/// The subarea offseted by block indices
public JpegPixelArea GetOffsetedSubAreaForBlock(int bx, int by)
{
int offset = this.Offset + (8 * ((by * this.Stride) + bx));
return new JpegPixelArea(this.Pixels, this.Stride, offset);
}
///
/// Gets the row offset at the given position
///
/// The y-coordinate of the image.
/// The
public int GetRowOffset(int y)
{
return this.Offset + (y * this.Stride);
}
///
/// Load values to the pixel area from the given .
/// Level shift [-128.0, 128.0] floating point color values by +128, clip them to [0, 255], and convert them to
/// values
///
/// The block holding the color values
/// Temporal block provided by the caller
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public unsafe void LoadColorsFrom(Block8x8F* block, Block8x8F* temp)
{
// Level shift by +128, clip to [0, 255], and write to dst.
block->CopyColorsTo(new MutableSpan(this.Pixels, this.Offset), this.Stride, temp);
}
}
}